Как обновить реакт компонент из setTimeout
Проблема в следующем, после рендера компонента, в фоновом режиме (setTimeout) запускается некое "тяжелое" вычисление. Хотелось бы вывести процент выполнения задачи на экране. Но до тех пор, пока идет подсчет результата в цикле, обновлений никаких не происходит. Так же блокируется вывод времени. Вывод в консоль при этом происходит нормально. Буду очень признателен, если подскажете в чем проблема и пути ее решения. Код схематичный, просто цикл в {limit} проходов, который по идее должен обновлять компонент каждую 40 000 000 итерацию (числа в цикле взяты произвольно и зависят от производительности конкретного компьютера).
import React, {useState, useEffect} from 'react';
export default function Test ({limit}) {
const [time, setTime] = useState()
const [progress, setProgress] = useState( 0 );
useEffect(() => {
const interval = setInterval(() => setTime(new Date().toLocaleTimeString()), 1000);
const timer = setTimeout(() => {
for (let i = 1; i < limit; ++i) {
if ( i % 40000000 == 0 ) {
const pr = Math.round(i * 100 / limit);
console.log( pr );
setProgress( pr );
}
}
console.log("All done")
}, 2000 );
return () => {
clearTimeout( timer );
clearInterval( interval );
}
}, [])
return (
<div>{time} Выполнено {progress}%</div>
)
}
Ответы (2 шт):
я не эксперт в этом деле но как то так по моему
export const App = () => {
const [time, setTime] = useState(0)
const [progress, setProgress] = useState( 0 );
useEffect(() => {
setInterval(() => {
setTime(new Date().toLocaleTimeString())
}, 1000);
}, [])
useEffect(() => {
if(progress>100)return
let timer = setTimeout(() => {
setProgress((prev) => ++prev)
},1000)
return () => {
console.log(`object`);
clearTimeout(timer)
}
},[progress])
return (
<div>{time} Выполнено {progress}%</div>
)
}
Поток исполнения в бразуере всего один, поэтому задача, что забивает всё процессорное время вероятней всего не даёт реакту выполнять свой код (который вероятней всего работает асинхронно, но это чисто спекуляции). Как по мне, тяжёлые штуки надо отправлять в воркер отдельный воркер и там уж он пусть отправляет ответ раз в какое-то время о своём состоянии (https://developer.mozilla.org/ru/docs/Web/API/Worker)