2

I feel like I come across this issue often.

When chaining useEffects to be triggered after state changes, I find that some of the useEffects in the chain have overlapping dependencies which cause them both to be triggered rather than sequentially, after one sets to state.

Example: I am triggering a chain of useEffects when chapterIndex updates.

let [ chapterIndex, setChapterIndex ] = useState<number | null>(0);

let [textTransitioning, setTextTransitioning] = useState<'out' | 'in' | null>(null);

useEffect(() => {
    setTextTransitioning('out')
}, [chapterIndex])

useEffect(() => {
    if (chapterIndex !== null) {
        const {
            current: chapter = null
        } = chapterRefs.current[chapterIndex];
            
        if (textTransitioning === 'in') {
            chapter?.classList.add('in');
        }
    }
}, [textTransitioning, chapterIndex])

How do I prevent both from running when chapterIndex changes? I only want the second useEffect to run after the first useEffect sets to textTransitioning. When removing chapterIndex from the dependency array I get the error: 'React Hook useEffect has a missing dependency: 'chapterIndex'. Either include it or remove the dependency array.'

Andy Tran
  • 135
  • 2
  • 9
  • since you included `chapterIndex ` as dependency both will run when it changes. if you can explain what your trying to do we may can help you in different way of doing it – Besufkad Menji Sep 22 '20 at 09:57
  • Since I'm using `chapterIndex` within the second useEffect, if I remove it from the dependency array I get an error saying 'React Hook useEffect has a missing dependency: 'chapterIndex'. Either include it or remove the dependency array.' @BesufkadMenji – Andy Tran Sep 22 '20 at 10:00
  • check this answer: [https://stackoverflow.com/a/55854902/10239185] – Besufkad Menji Sep 22 '20 at 10:02

2 Answers2

1

You need to remove "chapterIndex" from array in second useEffect. So when first useEffect will run then it will updated the "textTransitioning" that will cause second useEffect trigger.

For more conditional execution of useEffect you can refer https://reactjs.org/docs/hooks-effect.html

0

useEffect takes 2 arguments. first is the function to invoke and the second is an array of variables called dependencies array. the second argument used for triggering the use effect while one of the variables in the array is changing. so if you don't want useEffect to be called when a specific variable is changed do not pass it in the dependencies array. your code should be like that:

let [ chapterIndex, setChapterIndex ] = useState<number | null>(0);

let [textTransitioning, setTextTransitioning] = useState<'out' | 'in' | null>(null);

useEffect(() => {
      setTextTransitioning('out')
}, [chapterIndex])

useEffect(() => {
 if (chapterIndex !== null) {
     const {
         current: chapter = null
     } = chapterRefs.current[chapterIndex];
         
     if (textTransitioning === 'in') {
         chapter?.classList.add('in');
     }
 }
}, [textTransitioning]

I think that is not very efficient to make one useEffect trigger the other but maybe I am not seeing the whole picture

Itay wazana
  • 229
  • 2
  • 9
  • Since I'm using `chapterIndex` within the second useEffect, if I remove it from the dependency array I get an error saying 'React Hook useEffect has a missing dependency: 'chapterIndex'. Either include it or remove the dependency array.' – Andy Tran Sep 22 '20 at 09:59
  • that warning is because the value of `chapterIndex` will refer to old render and that is not best practice as mentioned at `React` docs "If you use this optimization, make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect. Otherwise, your code will reference stale values from previous renders. Learn more about how to deal with functions and what to do when the array values change too often." you can read more about it [here](https://reactjs.org/docs/hooks-reference.html#useeffect) – Itay wazana Sep 22 '20 at 10:18
  • I really think the logic should be in 1 useEffect, that is my advice. – Itay wazana Sep 22 '20 at 10:20