Реагировать на процесс обновления с помощью интенсивных вычислений, используя setState - PullRequest
0 голосов
/ 14 октября 2019

У меня есть простой класс React, показывающий this.state.progress (число), и это состояние можно обновить с помощью функции updateProgress(progress).

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      progress: 0,
    }
  }

  updateProgress = (progress) => {this.setState({progress}); };
  render() {
    let {progress} = this.state;
    return <h1>{progress}</h1>;
  }
}

У меня есть функция с интенсивными вычислениями myHeavyFunc, для которойМне нужно показать индикатор выполнения. Я вызываю updateProgress функцию, которую я упомянул выше, используя переменную цикла внутри myHeavyFunc.

myHeavyFunc = async (updateProgress) => {
    let loopLength = 1000000;
    updateProgress(0);
    for(let i=0; i<loopLength; i++) {
      // some processing happens here
      updateProgress((i+1)/loopLength);
    }
}

. Что происходит, так это то, что состояние обновляется, и я могу подтвердить это, запустив запись в консоль в обратном вызове setState, но компонент не рендерится до самого конца. Однако, если я включу небольшой sleep из 1 мс, тогда произойдет повторный рендеринг, обновления прогресса (очевидно, с огромной потерей времени, что я не предпочитаю).

JSFiddle здесь . Здесь я запускаю myHeavyFunc при нажатии на номер прогресса. Вы можете видеть, что когда await sleep(1) комментируется, onClick завершается через секунду, но НЕ показывает прогресс. Он даже не меняется для любых последующих кликов. С другой стороны, если это не прокомментировано, я получаю обновления о ходе выполнения, но это занимает вечность!

Я знаю, что React пакетирует обновления по соображениям производительности,но в моем случае я не вижу даже одного обновления, пока не закончится весь цикл. Кроме того, обратите внимание, что я НЕ ищу синхронную функцию setState, но мне нужно повторно выполнить рендеринг (по крайней мере, только для элемента progress) после установки состояния. Я в порядке, если он пропускает несколько обновлений прогресса из-за пакетирования, но я действительно ожидаю, что он покажет прогресс.

Есть ли способ запустить myHeavyFunc неблокирующим образом при обновлении прогресса в пользовательском интерфейсе? Как правильно обновлять прогресс интенсивных функций в React?

...