You need to enable JavaScript to run this app. React嵌套JSON受控组件表单出现受控非受控报错该如何解决
优惠活动
大模型
产品
解决方案
定价
更多

React嵌套JSON受控组件表单出现受控非受控报错该如何解决

问题根因

你遇到的controlled/uncontrolled报错和字段匹配问题有两个核心原因:

  • 初始值里petName/petBreed是嵌套在pet数组的第一个对象内,你把输入框的name直接设为根级字段,values根级不存在这两个字段,初始渲染时input的value为undefined,触发非受控组件逻辑,后续赋值后又转为受控组件,就会抛出对应错误
  • 你直接在value属性里写values.owner = values.owner.toUpperCase()属于直接修改state,违反React数据不可变原则,也会导致状态更新异常

第一步:修正输入框属性适配嵌套结构

要匹配你定义的初始值结构,输入框的name需要对应嵌套路径,同时禁止在value属性中直接修改state:

<Controls.Input
    label="Owner"
    name='owner'
    placeholder="Owner"
    {/* 不要在value里写=赋值,直接读取做转换即可 */}
    value={values.owner.toUpperCase()}
    onChange={handleInputChange}
/>
<Controls.Input
    label="PetName"
    {/* 用.区分数组索引和嵌套字段 */}
    name='pet.0.petName'
    placeholder="Pet Name"
    value={values.pet[0].petName.toUpperCase()}
    onChange={handleInputChange}
/>
<Controls.Input
    label="PetBreed"
    name='pet.0.petBreed'
    placeholder="Pet Breed"
    value={values.pet[0].petBreed}
    onChange={handleInputChange}
/>

第二步:改造useForm的handleInputChange支持嵌套字段更新

原来的handleInputChange只支持根级字段更新,需要修改为支持带.的嵌套路径解析:

export function useForm(initialFieldValues, validateOnChange=false, validate) {
    const [values, setValues] = useState(initialFieldValues);
    const [errors, setErrors] = useState({});

    const handleInputChange = event => {
        const { name, value } = event.target 
        // 解析嵌套路径
        const pathSegments = name.split('.');
        // 深拷贝原有values避免直接修改state
        const updatedValues = JSON.parse(JSON.stringify(values));
        let current = updatedValues;
        for (let i = 0; i < pathSegments.length - 1; i++) {
            const key = pathSegments[i];
            // 数字索引转为数值类型匹配数组
            current = current[/^\d+$/.test(key) ? Number(key) : key];
        }
        // 统一处理大写转换逻辑
        current[pathSegments.at(-1)] = name.includes('Name') || name === 'owner' ? value.toUpperCase() : value;
        
        setValues(updatedValues);
        if(validateOnChange) {
            validate({ [name]: value })
        }
    }

    return {
        values,
        setValues,
        errors,
        setErrors,
        handleInputChange,
    };
}

第三步:实现同个owner下添加多pet的逻辑

新增添加宠物的按钮,点击时给pet数组追加空的宠物对象,同时遍历pet数组动态生成对应输入框即可:

// 在PetsForm组件内新增添加宠物方法
const addNewPet = () => {
    setValues({
        ...values,
        pet: [...values.pet, { petName: '', petBreed: '' }]
    })
}

// 渲染部分替换原来写死的宠物输入框
<Controls.Input
    label="Owner"
    name='owner'
    placeholder="Owner"
    value={values.owner.toUpperCase()}
    onChange={handleInputChange}
/>
{values.pet.map((pet, index) => (
    <Box key={index}>
        <Controls.Input
            label={`宠物${index+1}名称`}
            name={`pet.${index}.petName`}
            placeholder="Pet Name"
            value={pet.petName.toUpperCase()}
            onChange={handleInputChange}
        />
        <Controls.Input
            label={`宠物${index+1}品种`}
            name={`pet.${index}.petBreed`}
            placeholder="Pet Breed"
            value={pet.petBreed}
            onChange={handleInputChange}
        />
    </Box>
))}
<Button onClick={addNewPet}>添加新宠物</Button>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 22:15:08