Reputation: 31
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?
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.
Upvotes: 3
Views: 103
Reputation: 31335
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:
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);
Upvotes: 3
Reputation: 10873
You just need to remove the if
condition in your async function:
const doSomethingAsync = async () => {
setLoading(true);
await somethingAsync(2000);
setLoading(false);
};
Upvotes: 1