2

I am new to React hooks and I am not sure how to achieve following goal. Let's say I have state1 and state2, and I use useEffect hook to call asyncFn1 and update state1.

Now I want to wait for state1 change and use state1 value to call asyncFn2 and update both state1 and state2. This asnycFn1 and asyncFn2 should only be called once.

If I just use another useEffect to call asyncFn2, I won't get the state1 value. How do I solve that?

const [state1, setState1] = useState(null);
const [state2, setState2] = useState(null);

const asyncFn1 = async() => {
  // async call to get state 1 data
  // setState1
}

const asyncFn2 = async(_state1) => {
  // use state1 data to make async call to get state 2 data
  // state2 data will be used to update both state1 and state2
}

useEffect(() => {
  asyncFn1();
}, [])
Orio Ryo
  • 53
  • 1
  • 6
  • Why do you want to update `state1` from `asyncFn2`? Does the input `_state1` to `asyncFn2` differ from the state you want to call `setState1` with? – Patrick Roberts Apr 25 '21 at 07:10
  • 1
    See https://stackoverflow.com/questions/59492626/stop-useeffect-from-running-on-mount/59492738#59492738, same logic, have a ref which acts as "called once" flag. – Dennis Vash Apr 25 '21 at 07:29
  • @PatrickRoberts Yes the state 1 will cause different asyncFn2 result which will be used to update the state1 again. – Orio Ryo Apr 26 '21 at 02:10
  • @DennisVash thank you! useRef is exactly what I needed. – Orio Ryo Apr 26 '21 at 02:12

1 Answers1

6

What you need here is a useEffect which has your state1 in the useEffect dependency array, so to trigger it any time your state1 value changes, as such:

useEffect(() => {
   state1 && asyncFn2()
}, [state1])

In case you want your asyncFn2 to trigger only once after you get the data for state1, you can just add a ref to check when that's being called:

const dataLoaded = useRef(false)

useEffect(() => {
   if(state1 && !dataLoaded.current) {
      asyncFn2()
   }
}, [state1])

const asyncFn2 = async () => {
   // Your logic here

   // Set dataLoaded on true once you have updated what you need successfully
   dataLoaded.current = true
}
ale917k
  • 1,236
  • 4
  • 11
  • 30
  • I see you fixed your example, but my statement is not wrong, previously you called `useCallback` inside `useEffect`, try this code and tell me about your findings – Dennis Vash Apr 25 '21 at 07:45
  • 1
    also, it should be `!dataLoadedRef.current` instead `!dataLoadedRef` which is always a truthy statement – Dennis Vash Apr 25 '21 at 07:46
  • True, that's a good point thanks for pointing - but what you said about not using hooks inside functions, what are functional components then? – ale917k Apr 25 '21 at 07:48
  • 1
    In React terms, there are "Function Components" and when saying "functions" those are just JS functions, see https://reactjs.org/docs/hooks-rules.html "Don’t call Hooks from regular JavaScript functions" – Dennis Vash Apr 25 '21 at 08:47