React component state wiped before component unmounted

1.6k Views Asked by At

If I return a function from useEffect I can be sure that that function will run when a component unmounts. But React seems to wipe the local state before it calls my unmounting function.

Consider this:

function Component () {

  const [setting, setSetting] = useState(false)

  useEffect(() => {

    setSetting(true)

    // This should be called when unmounting component
    return () => {

      console.log('Send setting to server before component is unmounted')
      console.log(setting) // false (expecting setting to be true)
      
    }
  }, [])
  
  return (
    <p>Setting is: {setting ? 'true' : 'false'}</p>
  )
}

Can anyone confirm that the expected behaviour is that the components state should be wiped? And, if that is the correct behaviour, how does one go about firing off the current component state to a server just before the component is unmounted?

To give some context, I'm debouncing a post request to a server in order to avoid firing it every time the user changes a setting. The debouncing works nicely, but I need a way to fire the request once a user navigates away from the page, as the queued debouncing method will no longer fire from the unmounted component.

2

There are 2 best solutions below

4
On

It's not that React "wipes out the state value", it's that you have closure on setting value (the value on-mount).

To get expected behavior you should use a ref and another useEffect to keep it up to date.

function Component() {
  const [setting, setSetting] = useState(false);

  const settingRef = useRef(setting);

  // Keep the value up to date
  // Use a ref to sync the value with component's life time
  useEffect(() => {
    settingRef.current = setting;
  }, [setting])
  

  // Execute a callback on unmount.
  // No closure on state value.
  useEffect(() => {
    const setting = settingRef.current;
    return () => {
      console.log(setting);
    };
  }, []);

  return <p>Setting is: {setting ? "true" : "false"}</p>;
}
0
On

I have faced same issue, resolved by below code,

<TextField
            required
            id="title"
            name="title"
            label="Course Title"
            fullWidth
            autoComplete="given-name"
            variant="standard"
            inputRef={titleRef}
            value={title}
            onChange={(event) => setTitle(event.target.value)}
          />



  const [title, setTitle] = React.useState(courseDetails.title);

  const titleRef = React.useRef(title);

  React.useEffect(() => {
    const titleData = titleRef.current;
    console.log(titleRef.current + "@@@@@");
    return () => {
      console.log(titleData.value + "****");
    };
  }, []);