Reputation: 11
When user change the select option, I need to do some time consuming work. While doing this work, I wanna show loading message, but it's not working
import React, { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
const [a, setA] = useState(1);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
sleep(2000);
console.log("finish");
setIsLoading(false);
}, [a]);
return (
<div>
{isLoading && "loding"}
<div>
<button
onClick={() => {
setIsLoading(true);
setA((a) => a + 1);
}}
>
button
</button>
<select
onChange={() => {
setIsLoading(true);
setA((a) => a + 1);
}}
>
{[1, 2, 3].map((i) => (
<option key={i} value={i}>
{i}
</option>
))}
</select>
</div>
</div>
);
}
function sleep(d) {
let t = Date.now();
while (Date.now() - t <= d);
}
but it's working on button onClick event. It looks so weird! And here is the online demo: https://codesandbox.io/s/modest-pasteur-8vrr0?file=/src/App.js:0-908
Upvotes: 1
Views: 1575
Reputation: 8804
You need to give react time to update the screen before starting the sleep/heavy work process.
Set a after a timer:
setTimeout(() => {
setA((a) => a + 1);
}, 50)
This will allow react to udapte screen with loading === true and after that, it will work on the process.
You could also try to use a webworker to offload the work form the main thread to not block the rendering. Check out useWorker.
Upvotes: 6