Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call a function after setting state is complete in useEffect?

I would like to run customFunction only when customEffect has finished setting isReady state. And customFunction should only run once no matter if the isReady was set to false or true as long as it was ran after it was set.

import customFunction from 'myFile';

export const smallComponent = () => {
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    const customEffect = async () => {
      try {
        const response = await get(
          `some-api.com`,
        );
        return setIsReady(response); // response can be true or false
      } catch {
        return null;
      }
    };

    customEffect();

    customFunction();
  }, []);

  return (
    <>Hello World</>
  )

}


I tried to add isReady as second useEffect argument, but then my customFunction is being run before the customEffect finishes and then again after the isReady is being set.

Also tried having in a separate useEffect, but still seems to run before the customEffect finishes.

like image 282
OFFLlNE Avatar asked Oct 23 '25 09:10

OFFLlNE


2 Answers

Set initial value to null and use separate useEffect as Kevin suggested (only without checking isReady true/false).

In this case setIsReady will change isReady from null to true/false and the second useEffect will be called.

import customFunction from 'myFile';

export const smallComponent = () => {
    const [isReady, setIsReady] = useState(null);

    useEffect(() => {
        const customEffect = async () => {
            try {
                const response = await get(
                    `some-api.com`,
                );
                return setIsReady(response);
            } catch {
                return null;
            }
        };

        customEffect();
    }, []);

    useEffect(() => {
       if (null === isReady) {
          return;
       }
       customFunction();
    }, [isReady]);

    return (
        <>Hello World</>
    )
}
like image 146
p1uton Avatar answered Oct 25 '25 21:10

p1uton


Since you want to cue an effect to run after the isReady state is set, and the value of isReady is irrelevant you can to use a second state value to indicate the first effect and state update has completed.

This will trigger the second effect to invoke customFunction but you don't want your component to remain in this state as from here any time the component rerenders the conditions will still be met. You'll want a third "state" to indicate the second effect has been triggered. Here you can use a React ref to indicate this.

export const smallComponent = () => {
  const [readySet, setReadySet] = useState(false);
  const [isReady, setIsReady] = useState(false);
  const customFunctionRunRef = useRef(false);

  useEffect(() => {
    const customEffect = async () => {
      try {
        const response = await get(
          `some-api.com`,
        );

        setReadySet(true); // to trigger second effect callback
        return setIsReady(response); // response can be true or false
      } catch {
        return null;
      }
    };

    customEffect();
  }, []);

  useEffect(() => {
    if (readySet && !customFunctionRunRef.current) {
      // won't run before readySet is true
      // won't run after customFunctionRunRef true
      customFunction();
      customFunctionRunRef.current = true;
    }
  }, [readySet]);

  return (
    <>Hello World</>
  );
}

Better solution borrowed from @p1uton. Use null isReady state to indicate customFunction shouldn't invoke yet, and the ref to keep it from being invoked after.

export const smallComponent = () => {
  const [isReady, setIsReady] = useState(null);
  const customFunctionRunRef = useRef(false);

  useEffect(() => {
    const customEffect = async () => {
      try {
        const response = await get(
          `some-api.com`,
        );

        return setIsReady(response); // response can be true or false
      } catch {
        return null;
      }
    };

    customEffect();
  }, []);

  useEffect(() => {
    if (isReady !== null && !customFunctionRunRef.current) {
      // won't run before isReady is non-null
      // won't run after customFunctionRunRef true
      customFunction();
      customFunctionRunRef.current = true;
    }
  }, [isReady]);

  return (
    <>Hello World</>
  );
}
like image 44
Drew Reese Avatar answered Oct 25 '25 21:10

Drew Reese



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!