React组件接收对象类型props变更时未更新,如何循环对象属性生成表单?
问题原因分析
你的代码无法正常更新的核心原因有两点:
- 使用了
defaultValue为input赋值:该属性是非受控组件专属属性,仅在组件首次挂载时生效,后续data状态更新时不会同步修改input的显示值。你修改为value后可以正常更新,是因为value是受控属性,会跟随绑定的状态实时同步。 - 依赖对比的潜在问题:
useEffect的依赖项是对象类型的row,React依赖对比默认是浅比较,如果父组件更新row时是直接修改原对象属性(而非生成新的对象实例),浅比较会判定row没有变化,useEffect不会触发更新。建议父组件更新row时使用新对象:setRow(prev => ({...prev, 要修改的属性: '新值'}))。
循环遍历生成表单的解决方案
方案1:受控表单实现(推荐)
受控表单方便后续做校验、数据收集,是React官方推荐的表单处理方式:
import React, {useState, useEffect} from "react"; const Form = ({row}) => { const [data, setData] = useState(row); useEffect(() => { setData(row); }, [row]); // 同步用户输入到状态 const handleChange = (e) => { const {name, value} = e.target; setData(prev => ({...prev, [name]: value})); }; return ( <> {Object.keys(data).map((head) => { // 遍历生成元素必须加唯一key,避免diff异常 return ( <input key={head} type="text" name={head} value={data[head] ?? ""} onChange={handleChange} /> ); })} </> ); }; export default Form;
方案2:非受控表单实现
如果你不需要实时同步输入到状态,坚持用defaultValue,可以通过修改key属性触发input重绘:
import React, {useState, useEffect} from "react"; const Form = ({row}) => { const [data, setData] = useState(row); useEffect(() => { setData(row); }, [row]); return ( <> {Object.keys(data).map((head) => { // key中加入row的唯一标识,row变化时key变化,React会销毁旧input重新创建,defaultValue会重新赋值 return ( <input key={`${row.ID}-${head}`} type="text" name={head} defaultValue={data[head] ?? ""} /> ); })} </> ); };
如果row没有唯一ID,可以用key={${JSON.stringify(row)}-${head}}替代,仅适合row结构不复杂的场景。
补充注意事项
- 普通业务对象遍历属性用
Object.keys即可,只有需要遍历不可枚举属性时才需要用Object.getOwnPropertyNames - 所有遍历生成的React列表元素必须加唯一
key属性,避免渲染异常和性能问题
内容的提问来源于stack exchange,提问作者user13688715
相关产品推荐
相关产品推荐

