skip to Main Content

I am using a useEffect hook with two depencies as follows:

useEffect(() => { ..... }, [apiData, currentMeasurements]);

Note that, the apiData is obtained through useLazyQuery of apollo/client.

Now upon save (say, saving or submission of form), two dependencies change at a time i.e apiData is got and currentMeasurements are also set to new array using setState, (i.e, setCurrentMeasurements([])).

Since API call takes time, React is executing useEffect once when currentMeasurements are set, and once again when I get the API response back.

But this isn’t the expected behavior. This is causing rendering the old values on the screen for the first time when useEffect is rendered (because of changes in currentMeasurements) and after a couple of seconds, new data is rendered (when useEffect again runs because we get newApiData).

How to make useEffect run only when I get the API response back? or in other words, how to make useEffect run only when I get two dependencies ready to be passed in useEffect.

Things I tried but didn’t work:
Using setTimeOut (with custom time) for updating currentMeasurements, but this causes problems when API response is delayed.

2

Answers


  1. You can save both dependencies as refs, and then check if both changed. If not do nothing. If it did, update the ref.

    const changedRef = useRef({});
    
    useEffect(() => { 
      if(changedRef.current.currentMeasurements !== currentMeasurements &&
         changedRef.current.apiData !== apiData) {
        
        ... // do something
        
        changedRef.current = {
          apiData
          currentMeasurements
        };
      }
    }, [apiData, currentMeasurements]);
    

    However, it’s easier to use a breaking condition – ie if the length of currentMeasurements is 0, don’t do anything inside the useEffect:

    useEffect(() => { 
      if(currentMeasurements.length === 0) return;
      
      ... // do something
    
    }, [apiData, currentMeasurements]);
    
    Login or Signup to reply.
  2. You can Compare their initial value, If any of them persist it then don’t execute the side effect

    useEffect(()=>{
    
    if(currentMeasurements.length == 0 || apiData == InitialValue) return;
    
    // do something with apiData and currentMeasurements
    
    }, [apiData, currentMeasurements])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search