React.js在render外部访问state异常:删除绘制直线时状态数组读取错误
问题根因
你遇到的是React的经典闭包陷阱问题:给线条绑定双击事件时,事件处理函数捕获了当前渲染周期内的allPaths状态快照,后续allPaths更新后,已绑定的旧事件处理函数仍然只会读取绑定时的旧状态,无法获取最新值。
对应的现象解释:
- 绘制第一条线时绑定的双击事件,捕获的是初始空
allPaths,因此双击第一条线时会打印空数组 - 绘制第四条线时绑定的双击事件,捕获的是创建第四条线之前的
allPaths(仅包含前3条线),因此双击第四条线时会打印长度为3的数组 - render函数每次状态更新都会重新执行,所以能拿到最新的
allPaths,打印结果正常 - codesandbox环境崩溃大概率是基于旧状态操作数组时触发了索引越界、无效引用等运行时异常。
解决方案
优先推荐成本最低的函数式更新方案:
修改删除逻辑中的setAllPaths调用,不要直接基于当前作用域的allPaths过滤,改用函数式更新形式,回调参数永远是最新的状态值:
// 错误写法 setAllPaths(allPaths.filter(path => path.id !== targetLineId)) // 正确写法 setAllPaths(prevPaths => prevPaths.filter(path => path.id !== targetLineId))
如果有其他需要读取最新allPaths的场景,也可以用ref同步状态的方案:
const allPathsRef = useRef(allPaths) // 每次allPaths更新时同步ref值 useEffect(() => { allPathsRef.current = allPaths }, [allPaths]) // 事件处理中从ref读取最新状态 const handleDblClick = (targetId) => { setAllPaths(allPathsRef.current.filter(path => path.id !== targetId)) }
内容的提问来源于stack exchange,提问作者Ricardo Sanchez
相关产品推荐
相关产品推荐

