score:0

it is a normal behaviour setstate will produce only a single re-render at the end of the event even if you used await, try to add a console.log inside your component you will see returnedmessage moved to 'new'

// app.js
import react from "react";
import useemail from "./useemail";

export default function app() {
  const { returnedmessage, send } = useemail();
  console.log("returnmessage post", returnedmessage); // in last render it will be new so it will change the view
  const run = async () => {
    console.log("returnmessage pre", returnedmessage);
    await send();
  };
  return (
    <div classname="app">
      <h2>click and wait for 1 second</h2>
      <button onclick={run}>click me</button>
      <h2>returned message:</h2>
      <p>{returnedmessage}</p>
      <button onclick={() => window.location.reload()}>
        reload to test again
      </button>
      <p>
        it prints "new", but logs "old"
        <br />
        even if i await send()...?
      </p>
    </div>
  );
}

score:0

one thing that i noted, from your custom react hook, you are returning an async function. which is this:

async () => {
    // fake fetch
    const whatever = await fetch(
      "https://jsonplaceholder.typicode.com/todos/1"
    );
    setreturnedmessage("new");
  };

and within your app component, you are accessing the custom hook where send is pointing to this async function. right?

now when you are calling your async function you are trying to do:

await send();

why await here again, since we already have an await inside of our function.

when you do this you are basically waiting for a promise() here, since every async function returns a promise even when nothing is returned.

i feel the implementation of custom hook should change or calling the hook has to be different.

on top of this setstate() is itself an asynchronous action. that is not in our control to tell when the state will update :)

score:1

you can do the job using useref.

it seems you can't access the updated value without running the hook again. with useref you'll get a reference and you can access the data at any time, without running the hook again.

// useemail.js

export default function useemail(message) {
  const messageref = react.useref("old");

  const send = async () => {
    // fake fetch
    const whatever = await fetch(
      "https://jsonplaceholder.typicode.com/todos/1"
    );

    messageref.current = "new";
  };

  return {
    messageref,
    send
  };
}
// app.js

export default function app() {
  const { messageref, send } = useemail();
  const run = async () => {
    console.log("returnmessage pre", messageref.current);
    await send();
    console.log("returnmessage post", messageref.current);
  };

  return (
    <div classname="app">
      <h2>click and wait for 1 second</h2>
      <button onclick={run}>click me</button>
      <h2>returned message:</h2>
      <p>{returnedmessage}</p>
      <button onclick={() => window.location.reload()}>
        reload to test again
      </button>
      <p>
        it prints "new", but logs "old"
        <br />
        even if i await send()...?
      </p>
    </div>
  );
}

enter image description here

score:1

you have 2 async functions in your custom hook.

  • your fetch (which one you await)
  • setstate

so even if you await for the fetch, your setstate is still asynchronous:

  • console.log("returnmessage pre", returnedmessage); //old
  • fetch
  • await fetch to complete
  • fetch complete
  • trigger setstate
  • function send() returns undefined (because no return is defined)
  • console.log("returnmessage post", returnedmessage); //old
  • state is updated (async setstate is complete)
  • returnedmessage is updated
  • component re-renders

if you want to have actions depending on when returnedmessage is changed, you'll have to use useeffect in your component

useeffect(() => {
    if (returnedmessage === "old") return; // do nothing here
    // returnedmessage !== "old" so assume it's "new"
    // do something...
}, [returnedmessage]);

Related Query

More Query from same tag