简体   繁体   中英

Returning a callback from useEffect

Sorry for the newbie question:

I'm using useEffect to avoid setting state on an unmounted component, and I was wondering why does this work:

useEffect(() => {
        let isMounted = true
        actions.getCourseDetails(fullUrl)
            .then(data => {
                if (isMounted) {
                    actions.setOwner(data.course.Student.id);
                    setDetails(data.course);
                }
            });
        return () => {
            isMounted = false;
        }
    }, [actions, fullUrl]);

...but when I return a variable instead of a callback it doesn't work?:

useEffect(() => {
        let isMounted = true
        actions.getCourseDetails(fullUrl)
            .then(data => {
                if (isMounted) {
                    actions.setOwner(data.course.Student.id);
                    setDetails(data.course);
                }
            });
        isMounted = false;
        return isMounted;     //returning a variable instead of a callback
    }, [actions, fullUrl]);

Thanks!

The syntax of useEffect is to optionally return a dispose function. React will call this dispose function ONLY when one of the dependencies changes or when it unmounts. to "release" stuff that no longer relevant.

For example, you want to wait X seconds after the render, and then change the state:

useEffect(() => {
   setTimeout(() => setState('Timeout!', timeToWait));
}, [timeToWait])

Imagen that this component mounts and then after one second unmounts. Without a dispose function the timer will run and React will try to run setState on unmounted component, this will result in an error.

The proper way to do it is to use the dispose function:

useEffect(() => {
   const id = setTimeout(() => setState('Timeout!', timeToWait));
   return () => clearTimeout(id);
}, [timeToWait])

So every time the timeToWait dependency changes for some reason, the dispose function will stop the timer and the next render will create a new one with the new value. or when the component unmounts.

In your example, the order of execution will be:

  1. Define isMounted and set it to true
  2. Start async action (this will run next tick)
  3. Set isMounted to false
  4. return a variable (Not a function)

So you have 2 problems in your (Not-working) example. you don't return a dispose function, and you change isMounted to false almost immediately after you define it. when the promise will run the isMounted will be false no matter what. If you'd use a dispose function (The working example), only when React will call it the isMounted to turn to false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM