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

React递归更新嵌套对象字段并返回新对象的实现问题

解决方案:React中嵌套对象的动态更新实现

核心问题分析

你的原有代码存在三个关键缺陷:

  1. 缺少路径追踪:递归渲染时未记录当前字段在根对象中的完整路径,导致无法定位嵌套字段的位置
  2. 状态更新错误:直接修改局部对象而非通过React状态 setter 更新根状态,无法触发组件重渲染
  3. 非受控组件:使用defaultValue而非受控的value属性,导致输入框无法同步状态变化

完整实现代码

1. 父组件(状态管理)

import { useState } from 'react';
import { customerDraft } from './your-file-path';
import Inputs from './Inputs';

function CustomerForm() {
  // 初始化状态:深拷贝原始对象避免污染源数据
  const [customer, setCustomer] = useState(() => 
    JSON.parse(JSON.stringify(customerDraft))
  );

  // 处理输入变化:接收完整路径和新值
  const handleChange = (path, value) => {
    setCustomer(prevState => updateNestedObject(prevState, path, value));
  };

  // 不可变更新嵌套对象的核心工具函数
  const updateNestedObject = (obj, path, value) => {
    if (path.length === 0) return value;
    const [firstKey, ...remainingPath] = path;
    // 创建当前层级的副本,避免直接修改原对象
    const newObj = { ...obj };
    // 递归更新嵌套层级
    newObj[firstKey] = updateNestedObject(newObj[firstKey], remainingPath, value);
    return newObj;
  };

  return (
    <div>
      <Inputs data={customer} onChange={handleChange} path={[]} />
      {/* 可选:实时预览更新后的对象 */}
      <pre style={{ marginTop: '2em' }}>{JSON.stringify(customer, null, 2)}</pre>
    </div>
  );
}

export default CustomerForm;

2. 递归输入组件

import { FormControl, InputLabel, Input } from '@mui/material';

const Inputs = ({ data, onChange, path }) => {
  return (
    <form style={{ display: 'flex', flexWrap: 'wrap', gap: '2em' }}>
      {Object.keys(data).map((key) => {
        const currentPath = [...path, key];
        
        // 递归渲染嵌套对象
        if (data[key] !== null && typeof data[key] === 'object') {
          return (
            <Inputs 
              key={key} 
              data={data[key]} 
              onChange={onChange} 
              path={currentPath} 
            />
          );
        }

        // 渲染基础类型输入框
        return (
          <FormControl key={key}>
            <InputLabel>{key}</InputLabel>
            <Input
              value={data[key]} // 受控组件:绑定状态值
              onInput={(e) => onChange(currentPath, e.target.value)}
            />
          </FormControl>
        );
      })}
    </form>
  );
};

export default Inputs;

关键改进点解释

  1. 路径追踪:

    • 通过path prop传递当前字段在根对象中的完整路径(如['metadata', 'birthDate'])
    • 递归渲染时自动扩展路径,确保每个输入框都能准确报告自己在对象中的位置
  2. 不可变更新:

    • updateNestedObject函数递归创建每个层级的对象副本,完全避免直接修改原状态
    • 只有目标字段所在的层级会被更新,其余层级保持引用不变,优化性能
  3. 受控组件:

    • 使用value={data[key]}替代defaultValue,确保输入框始终与状态同步
    • 状态更新后自动触发输入框值的更新,实现双向绑定效果

替代优化方案

  • 如果环境支持,可以用structuredClone()替代JSON.parse(JSON.stringify())进行深拷贝,支持更多数据类型(如Date、Map等)
  • 对于复杂嵌套结构,可以使用Immer库简化不可变更新逻辑,减少手动编写递归代码的工作量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:45:33