React useEffect cleanup with current props

前端 未结 3 1473
野趣味
野趣味 2021-01-18 02:21

I ran into a need of cleaning a useEffect when component is unmounted but with an access to the current props. Like componentWillUnmount can do by getting this.props.whateve

相关标签:
3条回答
  • 2021-01-18 02:34

    Since you passed empty array as dependency list for useEffect, your effect function only gets registered the first time. At that time, the value of count was 0. And that is the value of count which gets attached to the function inside useEffect. If you want to get hold of the latest count value, you need your useEffect to run on every render. Remove the empty array dependency.

    useEffect(() => {
      return () => console.log(count);
    })
    

    or use count as the dependency. That way, your effect function is created anew every time count changes and a new cleanup function is also created which has access to the latest count value.

    useEffect(() => {
      return () => console.log(count);
    }, [count])
    
    0 讨论(0)
  • 2021-01-18 02:36

    You need to track count in useEffect:

    import React, { useEffect } from "react";
    
    const B = ({ count }) => {
      useEffect(() => {
        return () => console.log(count);
      }, [count]);
    
      return <div>{count}</div>;
    };
    
    export default B;
    
    0 讨论(0)
  • 2021-01-18 02:43

    Was referenced to this question from another one so will do a bit of grave digging for it since there is no accepted answer.

    The behaviour you want can never happen because B never renders with a count value of 5, component A will not render component B when count is 5 because it'll render unmounted instead of B, the last value B is rendered with will be 4.

    If you want B to log the last value it had for count when it unmounts you can do the following:

    Note that effects executes after all components have rendered

    const useIsMounted = () => {
      const isMounted = React.useRef(false);
      React.useEffect(() => {
        isMounted.current = true;
        return () => (isMounted.current = false);
      }, []);
      return isMounted;
    };
    const B = ({ count }) => {
      const mounted = useIsMounted();
      React.useEffect(() => {
        // eslint-disable-next-line react-hooks/exhaustive-deps
        return () => !mounted.current && console.log(count);
      }, [count, mounted]);
    
      return <div>{count}</div>;
    };
    const A = () => {
      const [count, setCount] = React.useState(0);
      const handleClick = React.useCallback(() => {
        setCount(prevCount => prevCount + 1);
      }, []);
    
      if (count === 5) {
        //B will never be rendered with 5
        return <div>Unmounted</div>;
      }
    
      return (
        <React.Fragment>
          <B count={count} />
          <button onClick={handleClick}>Set count</button>
        </React.Fragment>
      );
    };
    
    ReactDOM.render(<A />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    0 讨论(0)
提交回复
热议问题