Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage async functions using React Hooks API

I am working with React Hooks and i am trying to update state then do something async and then do someting based on state. This doesn't work since the update state is not available inside the async function. How could you solve such a task using react hooks?

Demo

I basically tried to change the scope of the function but apparently its all immuteable which means the refrences inside the async functions points to old state.

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

// Constants
function somethingAsync(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

function App() {
  const [loading, setLoading] = React.useState(false);

  const doSomethingAsync = async () => {
    setLoading(true);
    await somethingAsync(2000);
    if (loading) {
      setLoading(false);
    }
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <p>Current Status: {loading ? "Loading" : "Not Loading"}</p>
      <button onClick={doSomethingAsync}>Do Something Async</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

I would like the loading flag to be reset back to false everytime the async function is done and this should be done based on state the have been updated while doing the async function. Right now it only works every second time due to the old references in the async scope.

like image 717
Thupi Avatar asked Jan 21 '26 06:01

Thupi


2 Answers

Just remove the if around your setLoading(false) call.

If you don't, that function will access a stale loading status. Because when that function was created, loading was false. So, after you run your async function, after the await, your function will resume, and even though loading is true it will see it as false. But you'll know that it will be true because you just set it and your App has re-rendered at the await statement. See the behavior below:

CodeSandbox

enter image description here

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

// Constants
function somethingAsync(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

function App() {
  const [loading, setLoading] = React.useState(false);
  console.log("App rendering...");

  const doSomethingAsync = async () => {
    setLoading(true);
    console.log("Before await...");
    await somethingAsync(2000);
    console.log("After await...");
    setLoading(false);
  };
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <p>Current Status: {loading ? "Loading" : "Not Loading"}</p>
      <button onClick={doSomethingAsync}>Do Something Async</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
like image 71
cbdeveloper Avatar answered Jan 22 '26 20:01

cbdeveloper


You just need to remove the if condition in your async function:

  const doSomethingAsync = async () => {
      setLoading(true);
      await somethingAsync(2000);
      setLoading(false);      
    };
like image 40
Clarity Avatar answered Jan 22 '26 20:01

Clarity



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!