React中useState调用被合并引发渲染与任务控制异常求助
React Promise进度更新与任务终止问题修复
问题根源
- 进度更新异常:循环中调用
setState时,始终引用闭包中的旧state值,每次更新都是基于初始的progress(0)计算,最终只会得到progress:1;同时React会批量合并异步的setState调用,导致中间进度无法显示。 - 任务无法终止:
startWork函数中的state是执行时的快照,后续cancelWork更新的total无法被循环内的判断读取到,终止逻辑失效。
修复代码
import React, { useState, useRef } from "react"; export default function () { const [state, setState] = useState({ progress: 0, total: 0 }); const isCancelledRef = useRef(false); const wait = (duration) => () => new Promise((resolve) => setTimeout(resolve, duration)); const startWork = async () => { const tasks = [wait(100), wait(200), wait(300), wait(400), wait(500)]; isCancelledRef.current = false; // 基于最新状态初始化进度 setState(prev => ({ ...prev, progress: 0, total: tasks.length })); for (const task of tasks) { // 实时检查取消标记 if (isCancelledRef.current) break; await task(); // 函数式更新,确保使用最新状态计算进度 setState(prev => ({ ...prev, progress: prev.progress + 1 })); } // 取消后重置状态 if (isCancelledRef.current) { setState(prev => ({ ...prev, total: 0, progress: 0 })); } }; const cancelWork = () => { isCancelledRef.current = true; setState(prev => ({ ...prev, total: 0, progress: 0 })); }; return ( <div> <p> {state.progress} / {state.total} </p> <button onClick={startWork}>Start</button> <button onClick={cancelWork}>Cancel</button> </div> ); }
关键修复点
- 函数式更新
setState:用setState(prev => newState)替代直接依赖闭包中的state,确保每次更新都基于最新状态值,解决进度计算错误和批量更新导致的状态不连贯问题。 useRef存储取消标记:useRef的current属性在组件生命周期中保持可变且可实时访问,避免闭包无法获取最新state的问题,确保Cancel按钮点击后能立即终止任务循环。- 实时检查取消状态:在每次任务执行前检查取消标记,一旦标记为
true就跳出循环,终止后续任务。
内容的提问来源于stack exchange,提问作者Jurakin
相关产品推荐
相关产品推荐

