I am performing a heavy computation in React, and I (1) don’t want the UI to block, and (2) want to display information about the process. I though that the useEffect
hook was the right way to approach this, but I’m not getting the right result.
What i would expect to happen is that the “Loading” part would show, the percentage would run gradually from 0 to 100, and when it’s finished it says “Finished”. What’s actually happening is that is starts at 0, then nothing during the whole of the counting, and then it jumps to “Finished” from nowhere.
What is the proper way to do this do both do the heavy lifting and also display the UI properly without blocking anything?
import { useEffect, useRef, useState } from "react";
export default function App() {
const [isLoading, setIsLoading] = useState<boolean>(true);
const [loadingPercentage, setLoadingPercentage] = useState<number>(0);
const loadingRef = useRef<any>();
useEffect(() => {
if (!loadingRef.current) {
return;
}
const MAX_COUNT = 1000000000;
let threshold = 0;
for (let count = 0; count < MAX_COUNT; ++count) {
///
/// Simulate some heavy-lifting process with process counter
///
if (count > threshold) {
const percentage = (count / MAX_COUNT) * 100;
setLoadingPercentage(percentage);
// console.log(percentage); <-- This just demonstrates that the % set actually gets hit
threshold += MAX_COUNT / 100;
}
}
setLoadingPercentage(100);
setIsLoading(false);
}, [loadingRef.current]);
return (
<div className="App">
<h1>Counting a whole lot of numbers</h1>
{isLoading ? (
<div>
<h2 ref={loadingRef}>{"Loading... " + loadingPercentage + "%"}</h2>
</div>
) : (
<h2>Finished counting!</h2>
)}
</div>
);
}
3