簡體   English   中英

為什么 getDerivedStateFromProps 不允許使用 state 更新重新渲染? componentWillReceiveProps 不是問題 - ReactJS

[英]Why getDerivedStateFromProps does not allow to re-render with the state update? Not a problem for componentWillReceiveProps - ReactJS

我正在嘗試從 componentWillReceiveProps 轉移到 getDerivedStateFromProps,在某些情況下,我成功了,但是當案例是 append 時,現有 state 的道具開始表現不同。 當對組件的 state 進行更新時,state 會發生變化(並且組件在更新后也會發生變化),但仍會呈現以前的 state。 使用 getDerivedStateFromProp 而不是 componentWillReceiveProps 時會發生一些奇怪的事情。 似乎該方法不能很好地處理“內部”更改。 在下面的示例中,我在 Child 上有 getDerivedStateFromProp 並且它可以工作,但因為只是渲染道具。 在一個更簡單的示例中也觀察到了這種行為,其中我沒有任何子組件並且只是呈現 state 更改。

下面的代碼顯示了一個子組件,用於打印/顯示 props 接收到的數據,同時使用刪除數據處理程序(從子組件交互中刪除存儲在 Parent 的數據)。 使用getDerivedStateFromProps()時,我無法訪問this.state和 prevState 並不意味着相同,因為 state 是累積的。 當我從子組件中刪除數據時,不會更新子組件的道具(使用 componentWillReceiveProps 時可以)。 所以,我找不到替代我的UNSAFE_componentWillReceiveProps的方法

組件WillReceiveProps:


  UNSAFE_componentWillReceiveProps(nextProps){
    this.setState({
      data: [...this.state.data,...nextProps.data]
    })
  }

getDerivedStateFromProps:

   static getDerivedStateFromProps(nextProps,state) {

    if (!isEqual(nextProps.data, state.data)) {
      return {
        data: [...state.data, ...nextProps.data]
      };
    }
    return null;
  }


按預期工作的原始代碼(在 Parent Comp 上的 getDerivedStateFromProps 之前。)

DataConsole - 父組件:

export class DataConsole extends Component {
  // Used for unsubscribing when our components unmount
  unsub = null;

  static defaultProps = {
    data: [],
  };

  constructor(props) {
    super(props);
    this.state = {
      data: [],
    };

    this.handleTableRowClick = this.handleTableRowClick.bind(this);
  }


   UNSAFE_componentWillReceiveProps(nextProps){
    this.setState({
      data: [...this.state.data,...nextProps.data]
    })
  }

  handleTableRowClick(key) {
    console.log(
      "handleTable",
      key,
      this.state.data[key],
      this.state.data.length
    );
     const e = this.state.data.splice(key, 1)
     //console.log("remove?", e , this.state.data.length)

    this.setState({
      undoDataRemove: e
    });
  }


  render() {
    return (
      <div>
        <Container
          fluid
          style={{ paddingLeft: 0, paddingRight: 0 }}
          className="DataContainer"
        >
          <Row noGutters>
            <Col sm={8} className="ConsoleTable">
              <div>
                <DataViewer
                  data={this.state.data}
                  rowClickHandler={this.handleTableRowClick}
                />
              </div>

       ...




DataViewer - 子組件

import isEqual from "react-fast-compare";
...

export class DataViewer extends Component {
  static defaultProps = {
    data: [],
  };

  constructor(props){
    super(props)
    this.state={data: []}
  }


  componentDidUpdate() {
    console.log("DataViewer updated");
  }

  static getDerivedStateFromProps(nextProps, prevProps) {

    console.log(nextProps, prevProps)
    if (!isEqual(nextProps.data, prevProps.data)) {
      return {
        data: nextProps.data
      };
    }
    return null;
  }


  render() {
    return (
      <div className={"TableData"}>
        <Table responsive="lg" striped borderless hover>
          <tbody>
            {this.state.data.map((elem, ids) => {
              if (!isEmpty(elem)) {
                return (
                  <tr key={ids} onClick={() => this.props.rowClickHandler(ids)}>
                    <td>{ids + 1}</td>
                    {Object.keys(elem).map(function (value, idx) {
                      return (
                        <td key={idx}>
                          {value}:{elem[value]}
                        </td>
                      );
                    })}
                  </tr>
                );
              } else {
                return null;
              }
            })}
          </tbody>
        </Table>
      </div>
    );
  }
}


您的代碼中有一個錯誤導致您的問題,它與getDerivedStateFromPropsUNSAFE_componentWillReceiveProps無關。

故障線是這樣的:

const e = this.state.data.splice(key, 1) 

它更改this.state.data而不調用setState 永遠不要那樣做。 唯一允許您對this.state進行任何更改的方法是通過this.setState或從 getDerivedStateFromProps 返回要合並到getDerivedStateFromProps的內容,而不是任何其他方式。

為了更輕松地應對 state 樹的深層變化,不可變庫可以派上用場。 immer目前是該類別中的頂級候選人之一。 使用immer ,您可以隨意修改state ,只要您使用模式this.setState(produce(this.state, newState => { /* change newState here */ }))將其包裝到produce調用中:

import produce from 'immer';

// ...

this.setState(produce(this.state, newState => {
  const e = newState.data.splice(key, 1);
  newState.undoDataRemove = e;
}));

希望,這可以提供幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM