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

React递归函数组件中如何实现递归状态的CRUD操作

递归嵌套状态的CRUD实现方案(无第三方库)

针对你的递归嵌套状态结构,核心思路是通过路径索引链定位节点,在顶层组件维护状态并提供操作回调,子组件通过传递路径和调用回调来触发状态更新(严格遵循React immutable更新原则)。以下是完整实现代码和关键说明:

完整修改后的代码

const initialData = {
    op: 0,
    values: [
        {
            op: 0,
            value: {
                values: [
                    {
                        op: 2,
                        value: {
                            values: []
                        }
                    }
                ]
            }
        },
        {
            op: 1,
            value: {
                values: []
            }
        }
    ]
};

// 工具函数:根据路径获取嵌套节点的深层拷贝并修改
const updateNestedNode = (obj, path, updater) => {
    if (path.length === 0) return updater(obj);
    const [key, ...restPath] = path;
    return {
        ...obj,
        values: obj.values.map((item, idx) => {
            if (idx === key) {
                return updateNestedNode(item, restPath, updater);
            }
            return item;
        })
    };
};

function App3() {
    const [mainState, setMainState] = React.useState(initialData);

    // 更新指定节点的op值
    const handleUpdateOp = (path, newOp) => {
        setMainState(prev => updateNestedNode(prev, path, node => ({
            ...node,
            op: parseInt(newOp) || 0
        })));
    };

    // 给指定节点添加子节点
    const handleAddChild = (path) => {
        const newChild = { op: 0, value: { values: [] } };
        setMainState(prev => updateNestedNode(prev, path, node => ({
            ...node,
            value: {
                ...node.value,
                values: [...(node.value?.values || []), newChild]
            }
        })));
    };

    // 删除指定节点
    const handleDeleteNode = (path) => {
        if (path.length === 0) return; // 根节点不允许删除
        const parentPath = path.slice(0, -1);
        const nodeIndex = path[path.length - 1];
        setMainState(prev => updateNestedNode(prev, parentPath, parentNode => ({
            ...parentNode,
            value: {
                ...parentNode.value,
                values: parentNode.value.values.filter((_, idx) => idx !== nodeIndex)
            }
        })));
    };

    // 添加根层级节点
    const handleAddRootNode = () => {
        setMainState(prev => ({
            ...prev,
            values: [...prev.values, { op: 0, value: { values: [] } }]
        }));
    };

    return (
        <div>
            {mainState.values.map((x, i) => (
                <RecursiveFn
                    key={i}
                    value={x}
                    path={[i]}
                    onUpdateOp={handleUpdateOp}
                    onAddChild={handleAddChild}
                    onDeleteNode={handleDeleteNode}
                />
            ))}
            <button onClick={handleAddRootNode}>添加根节点</button>
            <hr />
            <div>
                <pre>{JSON.stringify(mainState, null, 2)}</pre>
            </div>
        </div>
    );
}

function RecursiveFn({ value, path, onUpdateOp, onAddChild, onDeleteNode }) {
    return (
        <div style={{ padding: 5, margin: 10, paddingLeft: 20, border: '1px solid black' }}>
            <div>
                OP -
                <input
                    type="number"
                    value={value.op}
                    onChange={(e) => onUpdateOp(path, e.target.value)}
                />
            </div>
            {value.value?.values?.map((child, idx) => (
                <RecursiveFn
                    key={idx}
                    value={child}
                    path={[...path, idx]}
                    onUpdateOp={onUpdateOp}
                    onAddChild={onAddChild}
                    onDeleteNode={onDeleteNode}
                />
            ))}
            <button onClick={() => onAddChild(path)}>添加子节点</button>
            <button onClick={() => onDeleteNode(path)}>删除当前节点</button>
        </div>
    );
}

ReactDOM.render(<App3 />, document.getElementById("root"));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

关键实现说明

  1. 路径索引链(path)

    • 每个递归节点都会接收一个path数组,记录从根节点到当前节点的索引路径(比如根下第0个节点的子节点第1个,path就是[0,1])
    • 子节点传递给下一层时,会把当前索引追加到path中,确保能精准定位任意层级的节点
  2. Immutable状态更新

    • 用updateNestedNode工具函数递归复制嵌套对象,只修改目标节点,避免直接修改原state导致React无法检测更新
    • 所有状态更新都返回新的对象/数组,严格遵循React的state更新规则
  3. CRUD操作拆解

    • 更新(Update):通过path找到目标节点,修改op值并返回新对象
    • 新增(Create):根节点新增直接操作顶层values数组;子节点新增则找到目标节点的value.values数组,追加新节点
    • 删除(Delete):通过path获取父节点路径和当前节点索引,过滤父节点的values数组移除目标节点
    • 查询(Read):直接通过state传递给子组件渲染,无需额外处理

内容的提问来源于stack exchange,提问作者Gautam Parmar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:27:28