最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React useEffect cleanup with current props - Stack Overflow

programmeradmin0浏览0评论

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

Here is a small example: Click "set count" button 5 times and look at your console. You'll see 0 from the console.log in ponent B, regardless "count" will be 5

How to implement the behavior of getting current props in useEffect cleanup function (5 in my case)?

UPDATE: Passing count to the dependencies of useEffect won't help because:

  1. Cleanup will be invoked on every new count is passed to the props
  2. The last value will be 4 instead of the desired 5

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

Here is a small example: Click "set count" button 5 times and look at your console. You'll see 0 from the console.log in ponent B, regardless "count" will be 5 https://codesandbox.io/embed/vibrant-feather-v9f6o

How to implement the behavior of getting current props in useEffect cleanup function (5 in my case)?

UPDATE: Passing count to the dependencies of useEffect won't help because:

  1. Cleanup will be invoked on every new count is passed to the props
  2. The last value will be 4 instead of the desired 5
Share Improve this question edited Aug 14, 2019 at 6:30 Gena asked Aug 13, 2019 at 16:07 GenaGena 1,8072 gold badges16 silver badges19 bronze badges 3
  • I actually can't think of a way to do this. – Jonas Wilms Commented Aug 13, 2019 at 16:14
  • You can use useRef to store the current value – Jordan Commented Feb 11, 2020 at 20:52
  • @JonasWilms You can use an effect to see if a ponent is unmounted but you can never have it log 5 because ponent B is never rendered with a count value of 5. – HMR Commented Mar 21, 2020 at 14:00
Add a ment  | 

3 Answers 3

Reset to default 3

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, ponent A will not render ponent 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 ponents 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./ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

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;

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)

  1. 暂无评论