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

React状态中嵌套对象数组键重命名报错及解决方法问询

解决Redux嵌套数组键重命名的只读属性错误

问题原因

你遇到的错误是因为Redux的状态对象是不可变(只读)的,尤其是使用Redux Toolkit时,状态会被自动冻结(Object.freeze)。直接修改从useSelector获取的原对象(比如给原对象的children赋值)会触发只读属性报错——你不能直接修改Redux存储的原始状态。

正确实现方案

核心思路是:创建新的对象和数组完成键重命名,完全不触碰原Redux状态。写一个纯递归转换函数,配合useMemo缓存结果避免重复计算。

1. 纯递归转换函数

这个函数会遍历每个分类,创建新对象重命名键,递归处理嵌套的children:

const transformCategories = (categories) => {
  // 处理空数组或非数组的边界情况
  if (!categories || !Array.isArray(categories)) return [];

  return categories.map(category => {
    // 解构原对象,重命名目标键,保留其他属性
    const { _id: value, name: label, children, ...restProps } = category;
    
    const transformedItem = {
      value,
      label,
      ...restProps
    };

    // 递归处理children,生成新的children数组
    if (children && children.length > 0) {
      transformedItem.children = transformCategories(children);
    }

    return transformedItem;
  });
};

2. 在组件中使用(配合useMemo优化)

不需要用useEffect执行转换,直接在useSelector获取原始数据后,用useMemo缓存转换结果,只有当原始分类数据变化时才重新计算:

import { useSelector, useMemo } from 'react';

function CategoryComponent() {
  // 从Redux获取原始只读状态
  const rawCategories = useSelector(state => state.categories);

  // 缓存转换后的结果,避免每次渲染重复执行递归
  const transformedCategories = useMemo(() => {
    return transformCategories(rawCategories);
  }, [rawCategories]);

  // 后续直接使用transformedCategories即可
  return (
    <ul>
      {transformedCategories.map(item => (
        <li key={item.value}>
          {item.label}
          {item.children && (
            <ul>{/* 递归渲染子分类逻辑 */}</ul>
          )}
        </li>
      ))}
    </ul>
  );
}

为什么不用useEffect?

useEffect用于处理副作用(比如请求数据、操作DOM),而数据转换是纯计算逻辑,放在useMemo里更符合React设计理念,还能避免不必要的重渲染和状态修改风险。

内容的提问来源于stack exchange,提问作者Sunil Shrestha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 14:21:01