React State值在执行拖拽函数时总是重置为初始值
问题诊断与解决方案
核心原因:React闭包陷阱 + React-DnD回调未更新
你遇到的问题本质是闭包导致拖拽回调捕获了旧的State快照,再加上React-DnD的useDrop回调没有随着State更新而重新创建,所以第二次拖拽时handleDrop里拿到的始终是组件首次渲染时的schemaAssignments初始值。
具体解决步骤
1. 用useRef保存最新State的引用
在组件内添加一个Ref,实时同步最新的schemaAssignments值,这样拖拽回调能直接获取到最新数据:
import { useRef, useEffect } from 'react'; // 组件内部 const schemaAssignmentsRef = useRef(schemaAssignments); // 每次State更新时同步Ref useEffect(() => { schemaAssignmentsRef.current = schemaAssignments; }, [schemaAssignments]);
2. 用函数式更新修改State
修改handleDrop时,不要直接依赖当前的schemaAssignments,而是使用React的函数式State更新,确保基于最新的State快照修改:
const handleDrop = (item) => { // 从Ref获取最新值(可选,若仅用于读取) const currentAssignments = schemaAssignmentsRef.current; // 关键:用函数式更新获取最新的prevState setSchemaAssignments(prevAssignments => { // 执行你的赋值逻辑,注意保持不可变性 const newAssignments = [...prevAssignments]; const targetIndex = newAssignments.findIndex(obj => obj.id === item.id); if (targetIndex !== -1) { newAssignments[targetIndex] = { ...newAssignments[targetIndex], // 设置拖拽对应的特定值 assignedValue: item.value }; } return newAssignments; }); };
3. 确保useDrop回调随State更新
在useDrop的依赖数组中加入schemaAssignments(或schemaAssignmentsRef),让React-DnD在State变化时重新创建拖拽回调:
import { useDrop } from 'react-dnd'; const [{ isOver }, drop] = useDrop(() => ({ accept: 'YOUR_ITEM_TYPE', // 替换成你的拖拽元素类型 drop: handleDrop, collect: (monitor) => ({ isOver: monitor.isOver(), }), }), [schemaAssignments]); // 这里添加依赖,确保回调更新
4. 修正schemaAssignments的初始化逻辑
检查初始化schemaAssignments的useEffect,确保依赖项正确,当viewSchema变化时能同步更新:
useEffect(() => { // 用不可变方式初始化,避免直接引用原对象 setSchemaAssignments([...viewSchema.assignments]); }, [viewSchema]); // 依赖项必须包含viewSchema
额外排查点
- 如果你用了
useImmer,确保是通过produce函数修改State,而不是直接修改原对象:setViewSchema(produce(draft => { draft.assignments[targetIndex].assignedValue = item.value; })); - 检查组件是否被意外缓存(比如用了
React.memo但依赖项没设置对),导致State更新后没有触发重渲染。
内容的提问来源于stack exchange,提问作者JoshuaM
相关产品推荐
相关产品推荐

