6

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(); }, []) 
4
  • 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? Commented Apr 25, 2021 at 7:10
  • 1
    See stackoverflow.com/questions/59492626/…, same logic, have a ref which acts as "called once" flag. Commented Apr 25, 2021 at 7:29
  • @PatrickRoberts Yes the state 1 will cause different asyncFn2 result which will be used to update the state1 again. Commented Apr 26, 2021 at 2:10
  • @DennisVash thank you! useRef is exactly what I needed. Commented Apr 26, 2021 at 2:12

3 Answers 3

9

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 } 
Sign up to request clarification or add additional context in comments.

4 Comments

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
also, it should be !dataLoadedRef.current instead !dataLoadedRef which is always a truthy statement
True, that's a good point thanks for pointing - but what you said about not using hooks inside functions, what are functional components then?
In React terms, there are "Function Components" and when saying "functions" those are just JS functions, see reactjs.org/docs/hooks-rules.html "Don’t call Hooks from regular JavaScript functions"
0

I do this quite often and found that for me the most readable (and understandable) method is to use a hook that stores the previous value of something.

export function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }, [value]); return ref.current; } 

Then when I want create a side effect only when one specific value in my state changes I write:

const [fetching, setFetching] = useState(false); const prevFetching = usePrevious(fetching); useEffect(() => { if (prevFetching === true && fetching === false) { // Do something } }, [fetching, prevFetching]); 

Comments

0

To wait for the result of asyncFn1 to fetch the data for asyncFn2 you can use IIFE inside the useEffect and wait for asyncFn1 to complete executing and use the result to make the call to asyncFn2.

useEffect(() => { (async function(){ const result1 = await asyncFn1(); // Use the result to fetch the data for asyncFn2 const result2 = await asyncFn2(); // Update both state1 and state2 })() }, []) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.