使用useState更新状态时对象初始数据被重置,关联react-beautiful-dnd拖拽组件
问题根因
- 异步状态更新捕获旧值:你在axios请求回调中调用
setInitialData时,使用的是作用域闭包缓存的初始initialData值,两次请求的回调拿到的都是同一个初始空值的initialData,后执行的set操作会覆盖前一次的更新结果,导致其中一列数据被重置。 - Promise链写法不规范:你在then中直接执行console.log和第二个axios请求,没有正确返回Promise,导致异步执行顺序不可控;同时useEffect的回调函数不能直接标记为async,会导致返回Promise而非清理函数,触发React警告。
- 冗余状态依赖:你同时维护了
initialData和columns两个高度相似的状态,监听initialData更新columns的逻辑中也捕获了旧的columns值,可能引发额外的状态覆盖问题。
修复方案
核心优化为并行请求接口一次性更新状态、移除冗余状态、使用函数式状态更新避免闭包问题,修复后代码如下:
const MainComponent=()=>{ // 直接维护拖拽组件需要的columns状态,移除冗余的initialData const [columns, setColumns] = useState({ ['Mapped Courses']: { name: 'Mapped Courses', items: [] }, ['Available Courses']: { name: 'Available Courses', items: [] } }); // 拖拽结束逻辑使用函数式更新获取最新状态,避免闭包旧值问题 const onDragEnd = (result) => { if (!result.destination) return; const { source, destination } = result; setColumns(prevColumns => { if (source.droppableId !== destination.droppableId) { const sourceColumn = prevColumns[source.droppableId]; const destColumn = prevColumns[destination.droppableId]; const sourceItems = [...sourceColumn.items]; const destItems = [...destColumn.items]; const [removed] = sourceItems.splice(source.index, 1); destItems.splice(destination.index, 0, removed); return { ...prevColumns, [source.droppableId]: { ...sourceColumn, items: sourceItems }, [destination.droppableId]: { ...destColumn, items: destItems } }; } else { const column = prevColumns[source.droppableId]; const copiedItems = [...column.items]; const [removed] = copiedItems.splice(source.index, 1); copiedItems.splice(destination.index, 0, removed); return { ...prevColumns, [source.droppableId]: { ...column, items: copiedItems } }; } }) }; useEffect(()=>{ // 并行请求两个接口,一次性获取全部数据后更新状态,避免多次更新互相覆盖 Promise.all([ axios.get(`http://programsAPI/program`), axios.get('http://coursesAPI/courses') ]).then(([programRes, coursesRes]) => { setColumns({ ['Mapped Courses']: { name: 'Mapped Courses', items: programRes.data.courses.map((course) => ({ id: course.id, content: course.slug })) }, ['Available Courses']: { name: 'Available Courses', items: coursesRes.data.map((course) => ({ id: course._id, content: course.info.slug })) } }) }).catch((err) => console.log(err)) }, [programLoads]) return ( //HTML STARTS HERE ) }
内容的提问来源于stack exchange,提问作者Rupesh
相关产品推荐
相关产品推荐

