Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make code synchronous in useEffect

I know its not recommended to create add async to useEffect but how can I make sure my function is completely done before continuing

Here is my code

useEffect(
   () => {
         const RetrieverDataProcess = async () => {
             const GetMainListResults = await GetMainList(FORMSTATUS.ID);
             setMAINOBJECT(GetMainListResults); //useState
             console.log(2)
         }

         console.log(1);
         RetrieverDataProcess();
         console.log(99);

    }, [])

If I run in my console its showing

1

99

2

I was hopeing its

1

2

99

like image 678
Hawk Avatar asked Nov 28 '19 19:11

Hawk


People also ask

Does useEffect run synchronously?

The useLayoutEffect function is triggered synchronously before the DOM mutations are painted. However, the useEffect function is called after the DOM mutations are painted. I chose this example to make sure the browser actually has some changes to paint when the button is clicked, hence the animation.

Are hooks synchronous or asynchronous?

React useState hook is asynchronous!

How do I use async in useEffect?

Anti-Pattern: async function directly in the useEffect React can run this async function but can not run the cleanup function. Don't use raw async function directly in the useEffect. useEffect(async () => { console. log('Hi :)') return () => { console.info('Bye!

Is useState () synchronous?

TL;DR: useState is an asynchronous hook and it doesn't change the state immediately, it has to wait for the component to re-render. useRef is a synchronous hook that updates the state immediately and persists its value through the component's lifecycle, but it doesn't trigger a re-render.


3 Answers

Can you try this (not at pc right now)

useEffect(
   () => {
         const RetrieverDataProcess = async () => {
             const GetMainListResults = await GetMainList(FORMSTATUS.ID);
             setMAINOBJECT(GetMainListResults); //useState
             return console.log(2)
         }

         console.log(1);
         RetrieverDataProcess().then(()=>{
             console.log(99);
         });


    }, [])
like image 142
Renaldo Balaj Avatar answered Oct 13 '22 03:10

Renaldo Balaj


Are you doing this because you want the MAINOBJECT state property to be set by the time you're ready to execute console.log(99)?

If so, one thing you could do is use an additional useEffect hook that only executes when the state property MAINOBJECT updates:

useEffect(() => {
  if (MAINOBJECT) {
    console.log(99);
  }
}, [MAINOBJECT]);
like image 26
shawnyates Avatar answered Oct 13 '22 03:10

shawnyates


You may use an Immediately Invoked Function Expression or IFFY. This will also allow you to use async/await instead of going back to then-chaining.

Essentially you are wrapping the effect body in an async function, which you immediately invoke.

useEffect(() => {
     (async function anyName() {
         const RetrieverDataProcess = async () => {
             const GetMainListResults = await GetMainList(FORMSTATUS.ID);
             setMAINOBJECT(GetMainListResults); //useState
             console.log(2);
         }

         console.log(1);
         // now you can await the async function to make sure it completes
         await RetrieverDataProcess();
         console.log(99);
     // note the invocation:
     })();
}, [])
like image 25
Bastian Stein Avatar answered Oct 13 '22 04:10

Bastian Stein