静态getDerivedStateFromProps的行为不像componentwillreceiveprops吗?

时间:2019-05-08 07:30:17

标签: reactjs

嗨,我正在尝试在子组件中实现搜索,父组件将从服务器获取数据并将该数据传递给子组件

作为道具,现在子组件必须实现对该数据的搜索,我使用了componentwillreceiveprops,它已过时如何实现 这不使用componentwillreceiveprops,下面是我的代码

working example on fiddle

class Parent extends React.Component{
        constructor(props) {
            super(props);
            this.state = {
                data: []
            }
        }

        componentDidMount() {
            // mimic api call
            const data = [
                { key: 'react'}, { key: 'redux'},
                { key: 'javascript' }, { key: 'Ruby'} ,{key: 'angular'}
            ]
            setTimeout(this.setState({data}), 3000);
        }


        render() {
            return (
                <React.Fragment>
                    <ChildComponent data = {this.state.data}/>
                </React.Fragment>
            )
        }
    }


    class ChildComponent extends React.Component{
        constructor(props) {
            super(props);
            this.state = {
                data: []
            }
        }

        componentwillreceiveprops(nextProps){
            this.setState({data: nextProps.data})

        }

        search(e){
            console.log('props,', e.target.value)
            let searchedData =  this.props.data.filter(el => {
                return el.key.startsWith(e.target.value)
            })
            this.setState({data: searchedData})
        };

        render(){
            return(
                <div>
                    search for (react, redux, angular, ruby)
                    <br/> <br/> <br/>
                    <input type = 'text' onChange={this.search.bind(this)}/>
                    {this.state.data.map(d => {
                        return (<div key={d.key}>{d.key}</div>)
                    })}
                </div>
            )
        }

    }

2 个答案:

答案 0 :(得分:2)

getDerivedStateFromProps不能直接替代componentWillReceiveProps。它只是为了响应任何更新而更新状态,与componentWillReceiveProps不同,getDerivedStateFromProps在子项或父项的每次更新时都被触发,因此您不能简单地在没有任何条件检查的情况下更新状态。为了在道具更改时更新状态,您还需要将先前的道具也存储在child状态下,或者更新child的密钥,以便触发重新渲染

有两种可能的方法。以下是使用getDerivedStateFromProps

的第一种方法的示例
import React from "react";
import ReactDOM from "react-dom";
import _ from "lodash";

import "./styles.css";
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: []
    };
  }

  componentDidMount() {
    // mimic api call
    const data = [
      { key: "react" },
      { key: "redux" },
      { key: "javascript" },
      { key: "Ruby" },
      { key: "angular" }
    ];
    setTimeout(() => {
      this.setState({ data });
      setTimeout(() => {
        this.setState(prev => ({ data: [...prev.data, { key: "Golang" }] }));
      }, 3000);
    }, 3000);
  }

  render() {
    return (
      <React.Fragment>
        <ChildComponent data={this.state.data} />
      </React.Fragment>
    );
  }
}

class ChildComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: []
    };
  }

  static getDerivedStateFromProps(props, state) {
    if (!_.isEqual(props.data, state.prevData)) {
      return {
        data: props.data,
        prevData: state.data
      };
    } else {
      return {
        prevData: props.data
      };
    }
  }

  search(e) {
    console.log("props,", e.target.value);
    let searchedData = this.props.data.filter(el => {
      return el.key.startsWith(e.target.value);
    });
    this.setState({ data: searchedData });
  }

  render() {
    return (
      <div>
        search for (react, redux, angular, ruby)
        <br /> <br /> <br />
        <input type="text" onChange={this.search.bind(this)} />
        {this.state.data.map(d => {
          return <div key={d.key}>{d.key}</div>;
        })}
      </div>
    );
  }
}
function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);

Working DEMO


第二种方法涉及更改子组件的键,而不是实现getDerivedStateFromProps

import React from "react";
import ReactDOM from "react-dom";
import _ from "lodash";

import "./styles.css";
class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [],
      keyData: 0
    };
  }

  componentDidMount() {
    // mimic api call
    const data = [
      { key: "react" },
      { key: "redux" },
      { key: "javascript" },
      { key: "Ruby" },
      { key: "angular" }
    ];
    setTimeout(() => {
      this.setState(prev => ({ data, keyData: (prev.keyData + 1) % 10 }));
      setTimeout(() => {
        this.setState(prev => ({
          data: [...prev.data, { key: "Golang" }],
          keyData: (prev.keyData + 1) % 10
        }));
      }, 3000);
    }, 3000);
  }

  render() {
    return (
      <React.Fragment>
        <ChildComponent data={this.state.data} key={this.state.keyData} />
      </React.Fragment>
    );
  }
}

class ChildComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: props.data
    };
  }

  search(e) {
    console.log("props,", e.target.value);
    let searchedData = this.props.data.filter(el => {
      return el.key.startsWith(e.target.value);
    });
    this.setState({ data: searchedData });
  }

  render() {
    return (
      <div>
        search for (react, redux, angular, ruby)
        <br /> <br /> <br />
        <input type="text" onChange={this.search.bind(this)} />
        {this.state.data.map(d => {
          return <div key={d.key}>{d.key}</div>;
        })}
      </div>
    );
  }
}
function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Parent />, rootElement);

Working DEMO

当您知道子组件中会有相当多的更新,而来自父组件的更新将不那么频繁并且您必须比较getDerivedStateFromProps的道具被嵌套时,可以继续使用第二种方法。在这种情况下,实现getDerivedStateFromProps的性能将不如更新密钥,因为您将需要在每个渲染器上执行昂贵的计算。

答案 1 :(得分:0)

要使用新的componentWillReceiveProps()方法来实现您的getDerivedStateFromProps()行为,可以使用以下方法替换当前的componentwillreceiveprops()钩子:

static getDerivedStateFromProps(nextProps, state){

    /* Return the new state object that should result from nextProps */
    return { data : nextProps.data }
}

getDerivedStateFromProps()将在呈现组件之前被调用,如果返回非null值,则该返回值将成为组件的状态。

在您的情况下,<ChildComponent>组件的状态只有一个data字段,该字段直接从props填充,因此返回{ data : nextProps.data }就足以更新{{1} }状态字段以匹配传入的data道具。

通常的想法是,您可以使用此方法根据更改/传入的道具来更新组件的状态。

See this documentation有关data的更多信息-希望能对您有所帮助!

更新

另外要注意的是,似乎getDerivedStateFromProps()通过<Parent>方法更新状态的方式不正确。您应该更新它,如下所示:

setTimeout