如何解决React状态设置中的竞态条件问题?
问题原因及解决方案
问题出在React闭包陷阱和状态更新的方式上:
- 调用
loadingStream.subscribe时,回调函数捕获的data是当前组件渲染周期里的旧状态值——也就是初始状态中enableCopyToClipboard: true的版本。 - 当流返回数据触发回调时,执行
setData({...data, output: ...})会把旧状态里的enableCopyToClipboard: true重新覆盖进去,直接冲掉了之前设置的false。
修复方案:使用函数式状态更新
把setData改成接收函数的形式,每次更新都会基于最新的状态快照修改,不再依赖闭包里的旧值:
// 加载流前重置状态 setData({ ...data, output: '', enableCopyToClipboard: false, }); loadingStream(request).subscribe((response) => { resText.push(response.text); // 用函数式更新获取最新状态 setData(prevData => ({ ...prevData, output: resText.join(''), })); });
补充优化:避免普通变量丢失数据
如果resText是组件内部的普通变量,组件重新渲染时会被重置,建议用useRef保存这个数组:
import { useState, useRef } from 'react'; // 组件内部 const [data, setData] = useState({ input, output: '', enableCopyToClipboard: true, }); const resTextRef = useRef([]); // 监听流的代码 // 加载流前重置状态和缓存数组 setData(prev => ({ ...prev, output: '', enableCopyToClipboard: false })); resTextRef.current = []; loadingStream(request).subscribe((response) => { resTextRef.current.push(response.text); setData(prevData => ({ ...prevData, output: resTextRef.current.join(''), })); });
修改后,enableCopyToClipboard会保持你设置的false,直到你主动将其改回true。
内容的提问来源于stack exchange,提问作者Andrei V
相关产品推荐
相关产品推荐

