为什么我的React useState变量topicList未调用setTopicList也会更新?
为什么注释了setTopicList状态依然更新
你遇到的是React中非常典型的状态突变问题:
React的useState保存的引用类型(数组、对象)只对比引用地址是否变化,你代码里的topicList每个元素都是子数组,var newList = [...topicList]做的是浅拷贝——仅外层数组是新的,内层的所有子数组和原state里的子数组指向同一块内存地址。
你在resetCountsBelowDeleted中修改newList[i][4]的时候,本质是直接修改了原state中对应子数组的值,不需要调用setTopicList就已经改变了state的实际内容,这属于违反React状态更新规则的操作,只是碰巧跑出了你预期的结果。
为什么取消注释setTopicList后删除功能异常
你在removeItem函数中已经先调用了一次setTopicList(updatedList),而React的状态更新是异步批量执行的,此时topicList还没更新为删除后的新值。resetCountsBelowDeleted中生成newList用的还是删除操作前的旧topicList,取消注释后调用的setTopicList(newList)会直接覆盖掉前面删除操作的状态更新,自然就会出现删除失效、计数混乱等异常。
代码优化建议
- 首先把列表项从数组改为对象结构,不要用下标标记属性,可读性提升非常明显,示例结构:
{ id: Date.now(), // 不要用Math.random()当id,容易重复 text: '待办内容', } - 删除冗余状态:
topicCount完全等于topicList.length,不需要单独维护;不需要单独存排序序号,列表数组的下标天然就是排序顺序,重排序直接交换数组元素位置即可,省掉所有计算count、id映射的冗余函数。 - 重排序逻辑简化:不要手动计算元素坐标、监听全局鼠标事件,要么直接用HTML5原生拖放API,要么更简单的,给每个项加上上移/下移按钮,点击时直接操作数组:
const moveItem = (fromIndex, toIndex) => { const newList = [...topicList] const [item] = newList.splice(fromIndex, 1) newList.splice(toIndex, 0, item) setTopicList(newList) } - 修复
useEffect:你现在的useEffect没有加依赖数组,每次组件渲染都会执行,性能损耗很大,只需要在依赖数组里加[topicList],仅列表变化时才执行相关副作用。 - 禁止直接修改state:所有状态更新必须通过
setTopicList,不要直接修改state里的引用类型属性。
内容的提问来源于stack exchange,提问作者arl15b
相关产品推荐
相关产品推荐

