React Hook 的 componentWillReceiveProps、componentDidUpdate

IT技术 javascript reactjs react-hooks
2021-05-19 00:50:44

我遇到了两个挑战:

  • 即使根据 React 指南,不鼓励派生状态,但某些边缘情况仍然需要它。
    就带有 React Hook 的功能组件而言,React Hook的等效实现是什么,如果我确实需要在类组件中的派生状态,将在每个父渲染的 componentWillReceiveProps 中更新

见下面的代码示例:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: props.count > 100 ? 100 : props.count,
    }

  }

  /*What is the equivalent implementation when React Hook is used here componentWillReceiveProps*/
  componentWillReceiveProps(nextProps) {
    if (nextProps.count !== this.props.count) {
      this.setState({
        count: nextProps.count > 100 ? 100 : nextProps.count
      });
    }
  }

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

export default App;

  • 至于componentDidUpdate,componentDidUpdate在使用React Hook时有对应的,你必须像这样使用它,

      React.useEffect(() => {
        return () => {
    
         };
      }, [parentProp]);
    

    useEffect 的第二个参数确保代码仅在 prop 更改时执行,但是如果我想根据多个相应的 props 更改执行相应的任务怎么办如何使用 useEffect完成它

见下面的代码示例:

class App extends Component {


  /*What is the equivalent implementation when functional component with React Hook is used here */
  componentDidUpdate(prevProps, prevState) {
    if (prevProps.groupName !== this.props.groupName) {
      console.log('Let'
        's say, I do want to do some task here only when groupName differs');
    } else if (prevProps.companyName !== this.props.companyName) {
      console.log('Let'
        's say, I do want to do some different task here only when companyName differs');
    }

  }


  render() {
    /*for simplicity, render code is ignored*/
    return null;
  }
}

export default App;

4个回答

componentWillReceive可以使用useEffect钩子完成与旧props等效的react-hooks,只需指定我们要侦听依赖项数组中的更改的props即可。

IE:

export default (props) => {

    useEffect( () => {
        console.log('counter updated');
    }, [props.counter])

    return <div>Hi {props.counter}</div>
}

因为componentDidUpdate仅仅通过省略依赖数组,该useEffect函数将在每次重新渲染后调用。

IE:

export default (props) => {

    useEffect( () => {
        console.log('counter updated');
    })

    return <div>Hi {props.counter}</div>
}

您可以使用useMemo钩子来存储计算并放入props.count作为第二个参数给出的数组,以便在值发生变化时重新计算该值。

const { useState, useEffect, useMemo } = React;

function App() {
  const [count, setCount] = useState(50);

  useEffect(() => {
    setTimeout(() => {
      setCount(150);
    }, 2000);
  }, []);

  return <DisplayCount count={count} />;
}

function DisplayCount(props) {
  const count = useMemo(() => props.count > 100 ? 100 : props.count, [props.count]);

  return <div> {count} </div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="root"></div>

当单独的 props 改变时,做单独的效果最简单的方法是创建多个useEffect仅在单独的 props 改变时运行的钩子。

const { useState, useEffect } = React;

function App() {
  const [groupName, setGroupName] = useState('foo');
  const [companyName, setCompanyName] = useState('foo');

  useEffect(() => {
    setTimeout(() => {
      setGroupName('bar');
    }, 1000);
    setTimeout(() => {
      setCompanyName('bar');
    }, 2000);
  }, []);

  return <DisplayGroupCompany groupName={groupName} companyName={companyName} />;
}

function DisplayGroupCompany(props) {
  useEffect(() => {
    console.log("Let's say, I do want to do some task here only when groupName differs");
  }, [props.groupName])
  useEffect(() => {
    console.log("Let's say,I do want to do some different task here only when companyName differs");
  }, [props.companyName])

  return <div> {props.groupName} - {props.companyName} </div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="root"></div>

如果您在组件顶部使用 useMemo 钩子并使其依赖于您的所有props,则每次props更改时它都会在所有内容之前运行。useEffect 在更新渲染后触发,并且由于依赖于所有props,因此它在根据所有props重新渲染后触发。

const Component = (...props) => {
   // useState, useReducer if have
   useMemo(() => {
     // componentWillReceiveProps
   },[...props]);
   // ...other logic and stuff
   useEffect(() => {
     // componentDidUpdate
   }, [...props]);
};

setCount将触发重新渲染。使用useEffectwith[count]作为依赖项数组将确保钩子仅setCountcount的值更改调用

这就是你如何替换componentWillReceiveProps你可能用旧的基于类的 React 风格编写的任何逻辑。我发现“每个渲染都有自己的props和状态”原则很有用:如果您只想在特定props更改时触发重新渲染,您可以有多个useEffect钩子。

useEffect(() => {
  count > 100 ? setCount(100) : setCount(count)
}, [count]) 
 
useEffect(() => {
  console.log('groupName has changed');
  // do something with groupName
}, [groupName])
    
useEffect(() => {
  console.log('companyName has changed');
  // do something with companyName
}, [companyName])