0

我有一个看起来像这样的组件:


class Table extends Component {
  constructor(props) {
    super(props);

    this.columnDefs = columnDefs;
    this.state = {
      isLoading: true,
      showTimeoutModal: false,
      tableData: [],
      currentDate: null
    };
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    this.setState({
      isLoading: true,
      currentDate: this.props.currentDate
    });

    someApi.getData(this.props.currentDate).then(tableData => this.setState({
      tableData: tableData,
      isLoading: false
    }))
      .catch(error => {
        if (error.message === 'timeout') {
          this.setState({
            showTimeoutModal: true
          });
        } else {
          throw new Error(error.message);
        }
      });
  }

  onGridReady(params) {
    this.gridApi = params.api;
    this.gridApi.sizeColumnsToFit();
  }

  renderGrid() {
    const { tableData, isLoading, showTimeoutModal } = this.state;
    let currentView = null;
    console.log(this.props.currentDate);
    console.log(this.state.currentDate);
    if (!isLoading) {
      if (tableData) {
        currentView =
          <div>
            <AgGridReact
              columnDefs={this.columnDefs}
              rowData={tableData}
              pagination
              paginationPageSize={25}
              headerHeight="43"
              onGridReady={params => this.onGridReady(params)}
              rowSelection="single"
              animateRows="true" />
          </div>;
      } else {
        currentView = <h6>There is no job data to display!</h6>;
      }
    } else if (showTimeoutModal) {
      currentView = <div>
        <TimeoutModalComponent />
        <h6>Timed out</h6>
      </div>;

    } else {
      currentView = <LoadingComponent />;
    }

    return (
      <div>

        {currentView}
      </div>
    );
  }

  render() {
    return (
      <div>
        {this.renderGrid()}
      </div>
    );
  }

}

export default Table;

它从如下所示的 datepicker 组件获取 currentDate 属性:


class DatePicker extends Component {
  constructor(props) {
    super(props);
    this.onDateChange = this.onDateChange.bind(this);
    this.state = {
      currentDate: moment(),
      focused: false
    };
  }

onDateChange() {
    this.setState({
      currentDate: this.props.currentDate
    });
  }

  render() {
    return (
      <div className="form-group">


        <SingleDatePicker
          date={this.state.currentDate}
          onDateChange={this.onDateChange}
          focused={this.state.focused}
          onFocusChange={({ focused }) => this.setState({ focused: focused })}
        />
        <TableComponent currentDate={`${this.state.currentDate}`} onDateChange={this.onDateChange} />
      </div>

    );
  }
}

export default DatePicker;

当我从日期选择器中选择新日期时,子组件上的 this.props.currentDate 会更新。这是我想要的日期。但是,当该道具更新时,它不会使用新的预期数据重新渲染表格。我意识到我必须更新孩子的状态才能重新渲染表格。我试图通过设置 currentDate: this.props.currentDate 来设置 fetchData() 方法中的状态来做到这一点。但这不起作用,它不会实时更新状态,因此网格不会重新渲染。我想我在概念上遗漏了一些关于反应的东西,但我不确定是什么。我认为 datePicker 组件很好,因为它可以在选择日期时发送正确的日期,并且可以将该日期传递给表格组件。谁能告诉我为什么这个状态不会更新?或者更好的是,

编辑:我现在可以改变状态

componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.currentDate !== this.state.currentDate) {
  this.setState({currentDate: nextProps.currentDate});
}

}

但它仍然不会在更新时重新渲染表格。

4

2 回答 2

0

使用 componentDidUpdate(prevProps) 在 Table 和 DatePicker 组件中捕获道具更改事件。

避免使用 componentWillReceiveProps。

根据react.org,使用这种生命周期方法通常会导致错误和不一致

于 2019-12-16T20:07:10.153 回答
0

好的,所以您有多个我可以看到的问题:

  • 您正在管理您DatePickerTable组件中 currentDate 的状态,这是一个很大的危险信号,一个很大的 NO NO,您需要更好地理解“ Lifting State Up
  • 另一个问题是<TableComponent currentDate={${this.state.currentDate} }。现在,在我的脑海中,我不知道这是否真的导致你Table不重新渲染,但它仍然不是一般软件工程意义上的良好绑定。您不应该转换currentDate为字符串,您将 ref 松散到currentDateReact 为您管理的状态,并且 ref 更改是触发使用任何前端数据绑定库(Angular、Knockout、ReactJs、 Vue.js) 显示的组件currentDate可以在内部负责将字符串转换为在 HTML 中显示。

您希望将您的Table组件和DatePicker组件放在一个父组件中,该组件控制 Table 组件和组件的布局,DatePicker并管理这两个组件之间共享的状态。这种变化将彻底改变你的方法,让你解放思想,更好地管理你的 ReactJs 应用程序。这是“提升状态”。您会发现,在我建议的重构之后,您的重新渲染问题很可能甚至不存在。

于 2019-12-13T21:24:08.573 回答