1

I am new to React and would like some help on how to use useEffect(). I have a state machine implemented with Reducer and want to use useEffect() to update the state.

I have such state machine as below. At default the state is set as init and after sendEvent("INITIALIZE") is called the state gets updated to idle. I want to do this process inside useEffect().

enter image description here

But I have a function to be executed before calling sendEvent("INITIALIZE") so the order I want would look like this

  1. if current state is "init" then call handleInitialize() and wait until it gets executed
  2. handleInitialize() gets executed and returns a flag
  3. check the flag and sendEvent("INITIALIZE")

So far I have the following code and it seems that useEffect() can't be an async function

useEffect(() => {
    console.log("useEffect() -a");

    if (currentState === "init"){      
      let flag =  handleInitialize();
      console.log("flag" + flag);
      if (flag){
        setInitialized(true);
        console.log("initialize event INITIALIZE");
        sendEvent("INITIALIZE")
      }
    }

    console.log("useEffect() -x");
  }, [currentState, sendEvent]);

I have taken a look at React Hook Warnings for async function in useEffect: useEffect function must return a cleanup function or nothing .

I still see the problem even if I wrap this function with async. I tested with the following code

 useEffect(() => {
    console.log(AppName+":" +"useEffect() -a");

    async function update(){
      console.log(AppName+":" +"update() -a");

      try {
      if (currentState === "init"){      
        let flag =  await handleInitialize();
        console.log(AppName+":" +"flag" + flag);
        if (flag){
          setInitialized(true);
          console.log(AppName+":" +"initialized event INITIALIZE");
          sendEvent("INITIALIZE")
        }
      }
    } catch (error) {}
    console.log(AppName+":" +"update() -x");
  }

  update();

  console.log(AppName+":" +"useEffect() -x");
  }, [currentState, sendEvent]);

The print out for this is:

ExampleApp:EaxampleApp2: -a
ExampleApp.tsx:128 ExampleApp:switch statement:init
ExampleApp.tsx:94 ExampleApp:useEffect() -a
ExampleApp.tsx:97 ExampleApp:update() -a
ExampleApp.tsx:125 ExampleApp:useEffect() -x
ExampleApp.tsx:102 ExampleApp:flagtrue
ExampleApp.tsx:59 ExampleApp:EaxampleApp2: -a
ExampleApp.tsx:128 ExampleApp:switch statement:init
ExampleApp.tsx:105 ExampleApp:initialized event INITIALIZE
ExampleApp.tsx:59 ExampleApp:EaxampleApp2: -a
ExampleApp.tsx:128 ExampleApp:switch statement:idle
ExampleApp.tsx:120 ExampleApp:update() -x
ExampleApp.tsx:94 

I expected to see this order but the output above prints update() -x after useEffect() -x

ExampleApp:useEffect() -a
ExampleApp.tsx:97 ExampleApp:update() -a
ExampleApp.tsx:120 ExampleApp:update() -x
ExampleApp.tsx:125 ExampleApp:useEffect() -x

Please let me know if there is a way to do this.

Thanks,

takanoha
  • 183
  • 4
  • 17
  • Can you add to your question the code sample where you tried `async` and `await`? – jmargolisvt Apr 28 '21 at 03:07
  • @jmargolisvt I have added the code sample that didn't work. – takanoha Apr 28 '21 at 23:56
  • Whenever execution hits an `await`, control returns to the caller. Then at some point in the future after the async work is done, the code after the await will execute. So your `"useEffect() -x"` is supposed to come before `"update() -x"`. – windowsill Apr 29 '21 at 00:14
  • Besides that confusion, it looks like you're executing your steps in the correct order, no? – windowsill Apr 29 '21 at 00:15
  • @windowsill Thanks for the explanation. So there is no way to see "update() -x" before "useEffect() -x" ? This is a problem for me because I need to send an event such as "sendEvent("INITIALIZE")" before useEffect() id done :( – takanoha Apr 29 '21 at 00:22
  • If you want to do something after an await, just put it after the await in the async function. – windowsill Apr 29 '21 at 00:55

0 Answers0