React 将 useState 调用合并到单个渲染中

问题描述 投票:0回答:1

我尝试向用户报告承诺执行的进度。我遇到的问题是 React 似乎正在将我的

setState
调用合并到单个渲染中。

当我点击开始时,它闪烁

0 / 5
,然后保持
1 / 5
,其他时候它会高于1。还有一个问题是按下按钮时执行停止,因为
setState
没有是时候更新
total
了,从而在按下按钮之前停止代码(注释行)。下面的代码是我的尝试。

import React, { useState } from "react";

export default function ({}) {
  const [state, setState] = useState({ progress: 0, total: 0 });

  const wait = (duration) => () => new Promise((resolve) => setTimeout(resolve, duration));

  const startWork = async () => {
    const tasks = [wait(100), wait(200), wait(300), wait(400), wait(500)];

    setState({ ...state, progress: 0, total: tasks.length });

    for (const task of tasks) {
      // stop if cancelled
      //   if (state.total === 0) return;

      const data = await task();

      setState({ ...state, progress: state.progress + 1 });
    }
  };

  const cancelWork = () => {
    setState({ ...state, total: 0 });
  };

  return (
    <div>
      <p>
        {state.progress} / {state.total}
      </p>
      <button onClick={startWork}>Start</button>
      <button onClick={cancelWork}>Cancel</button>
    </div>
  );
}

reactjs react-hooks
1个回答
0
投票

setState
更新下一次渲染的状态。当你这样做时

setState({ ...state, progress: 0, total: tasks.length });
for (const task of tasks) {
  setState({ ...state, progress: state.progress + 1 });
}

state.progress
将是循环的每次迭代的初始值,因为它尚未重新渲染,因此每次您都将其设置为
0 + 1
(假设 state.progress 最初为 0)。

您可能想做的是:

let progress = state.progress || 0;
setState({ ...state, progress, total: tasks.length });
for (const task of tasks) {
    progress += 1;
    setState({ ...state, progress });
}

这样每次您调用

setState
时,您都会使用正确的进度值。

© www.soinside.com 2019 - 2024. All rights reserved.