You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中勾选复选框报Cannot add property 0错误的解决求助

React复选框勾选报错:无法添加属性0,对象不可扩展

问题现象

勾选复选框时触发如下错误,无法正常添加权限项:

Cannot add property 0, object is not extensible
TypeError: Cannot add property 0, object is not extensible
at Array.push ()
at handleCheckboxChange (http://localhost:5173/src_pages_authorized_role_rolesDetail_index_tsx.d2f40c44ee046000e94a.hot-update.js:97:35)
at onChange (http://localhost:5173/src_pages_authorized_role_rolesDetail_index_tsx.d2f40c44ee046000e94a.hot-update.js:188:24)

相关代码片段

组件状态与初始化

const [formData, setFormData] = useState<RoleFormData>({
  name: "",
  permissions: [],
});

useEffect(() => {
  if (addRole) {
    setFormData({
      name: addRole.name,
      permissions: addRole.permissions,
    });
  }
}, []);

复选框处理函数

const handleCheckboxChange = (
  permissionId: number,
  section: string,
  checkedValues: CheckboxValueType[]
) => {
  const updatedFormData = { ...formData };

  const permission = updatedFormData.permissions.find(
    per => per.permissionId === permissionId && per.section === section
  );

  if (permission) {
    permission.name =
      checkedValues.length > 0 ? String(checkedValues[0]) : "";
  } else {
    updatedFormData.permissions.push({
      permissionId,
      section,
      name: checkedValues.length > 0 ? String(checkedValues[0]) : "",
    });
  }

  setFormData(updatedFormData);
};

Redux初始状态与Reducer

// 初始状态
const initialState: IRoles = {
  rolesList: [],
  permissionList: [],
  permissionsBySection: {} as PermissionsBySection,
  addRole: {
    roleId: 0,
    name: "",
    permissions: [],
  },
  error: null,
  loading: false,
};

// Reducer
reducers: {
  resetRolesItem: () => initialState,
  updateAddRoles: (state, action: PayloadAction<UpdateAddRole>) => ({
    ...state,
    addRole: {
      ...state.addRole,
      ...action.payload,
    },
  }),
},

问题原因

Redux状态通常会被设置为不可扩展/冻结(比如Redux Toolkit默认配置、使用Immer或自定义中间件),防止直接修改原状态。当你在useEffect中直接将addRole.permissions赋值给formData.permissions时,formData.permissions引用的是Redux中不可扩展的原数组。即使浅拷贝了formData对象,里面的permissions数组还是原引用,调用push操作时就会触发“对象不可扩展”的错误。

解决方案

1. 初始化时深拷贝权限数组

在useEffect中初始化formData时,对addRole.permissions进行拷贝,切断与Redux原数组的引用:

useEffect(() => {
  if (addRole) {
    setFormData({
      name: addRole.name,
      // 浅拷贝数组,创建可扩展的新数组
      permissions: [...addRole.permissions],
      // 若数组元素是对象,需拷贝每个对象:
      // permissions: addRole.permissions.map(perm => ({ ...perm })),
    });
  }
}, []);

2. 处理函数中使用不可变更新方式

修改handleCheckboxChange,通过创建新数组/对象的方式更新状态,避免直接修改原引用:

const handleCheckboxChange = (
  permissionId: number,
  section: string,
  checkedValues: CheckboxValueType[]
) => {
  const name = checkedValues.length > 0 ? String(checkedValues[0]) : "";

  setFormData(prevFormData => {
    const existingIndex = prevFormData.permissions.findIndex(
      per => per.permissionId === permissionId && per.section === section
    );

    if (existingIndex !== -1) {
      // 更新已有权限项:创建新数组替换对应元素
      const updatedPermissions = [...prevFormData.permissions];
      updatedPermissions[existingIndex] = {
        ...updatedPermissions[existingIndex],
        name,
      };
      return { ...prevFormData, permissions: updatedPermissions };
    } else {
      // 添加新权限项:创建新数组追加元素
      return {
        ...prevFormData,
        permissions: [...prevFormData.permissions, { permissionId, section, name }],
      };
    }
  });
};

3. 确保Redux状态更新符合不可变性原则

确认Redux reducer中始终返回新的对象/数组,你的updateAddRoles已经做了浅拷贝,这部分是合规的。如果action.payload包含permissions,也要确保传入的是新数组而非原引用。

内容的提问来源于stack exchange,提问作者Shiva Giri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:15:06