JavaScript数组与React组件状态更新冲突问题排查
问题根源
departmentArray是定义在组件函数内部的普通局部变量,只要组件触发重渲染,这行let departmentArray = ([]);就会重新执行,直接把数组重置为空数组,之前存入的选中值会全部丢失。
保留状态更新代码时,点击复选框会调用setXxxCheck触发组件重渲染,数组被重置,自然无法正常记录选中值;删掉状态更新代码后,点击操作不会触发组件重渲染,局部变量不会被重置,所以数组的增删操作看起来是正常的——这只是没有触发重渲染带来的假象,并不是代码逻辑本身正确。
除此之外原写法还有两个明显问题:
- 直接用
push/splice修改原数组属于可变数据操作,不符合React状态更新的不可变要求 - 同时维护三个独立的复选框布尔状态、一个选中部门数组,属于同源数据重复存储,非常容易出现数据不一致的问题
修复方案
把选中部门列表也纳入React状态管理,用单一数据源维护所有选中状态,不需要额外维护三个单独的布尔值,代码更简洁也不会出现状态不同步的问题:
import { useState } from 'react'; import { Form } from 'react-bootstrap'; function DepartmentSelector() { // 仅用一个状态存储所有选中的部门 const [departmentArray, setDepartmentArray] = useState([]); function handleCheck(val) { setDepartmentArray(prevSelected => { const index = prevSelected.indexOf(val); if (index > -1) { // 已选中则过滤掉当前值,返回新数组 return prevSelected.filter(item => item !== val); } else { // 未选中则把当前值加入新数组 return [...prevSelected, val]; } }) } return ( <> <Form.Check name="department" onClick={() => handleCheck("Maintenance")} checked={departmentArray.includes("Maintenance")} /> <Form.Check name="department" onClick={() => handleCheck("Process")} checked={departmentArray.includes("Process")} /> <Form.Check name="department" onClick={() => handleCheck("Toolroom")} checked={departmentArray.includes("Toolroom")} /> </> ) }
修复后所有和选中相关的状态都存在React state中,重渲染时状态不会丢失,所有复选框的选中状态直接从同一个数组派生,不会出现数据冲突。
内容的提问来源于stack exchange,提问作者Nathan Field
相关产品推荐
相关产品推荐

