React通用表单组件处理嵌套对象时如何实现递归渲染?
递归实现方案
以下是修改后的完整可运行代码:
function GenericForm(props: any) { // 递归渲染函数,parentPath用于拼接嵌套字段的name/id避免重复 const renderFields = (currentObj: Record<string, any>, parentPath = '') => { return Object.entries(currentObj).map(([property, value]) => { // 拼接当前字段完整路径,嵌套字段格式为 父级属性.当前属性 const fullPath = parentPath ? `${parentPath}.${property}` : property; let type: string = ""; let isNestedObject = false; if (typeof value === "string") { type = "text"; } else if (typeof value === "number") { type = "number"; } else if (typeof value === "boolean") { type = "checkbox"; } else if (value instanceof Date) { type = "date"; } else if (typeof value === "object" && value !== null) { type = "hidden"; isNestedObject = true; } const fieldElements = [ <label key={`label-${fullPath}`} htmlFor={fullPath}> {property} </label>, <input key={`input-${fullPath}`} type={type} id={fullPath} name={fullPath} defaultValue={typeof value === 'object' && ! (value instanceof Date) ? JSON.stringify(value) : value as string | number | boolean} onChange={(newVal) => { // 按路径拆分实现嵌套属性赋值 const pathArr = fullPath.split('.'); let target = props.object; for (let i = 0; i < pathArr.length - 1; i++) { target = target[pathArr[i]]; } const finalVal = type === 'checkbox' ? newVal.target.checked : type === 'number' ? Number(newVal.target.value) : newVal.target.value; target[pathArr.at(-1)!] = finalVal; }} />, ]; // 嵌套对象递归渲染子属性,添加缩进区分层级 if (isNestedObject) { fieldElements.push( <div key={`nested-${fullPath}`} style={{ marginLeft: '20px', marginTop: '8px' }}> {renderFields(value, fullPath)} </div> ) } return fieldElements; }) } return ( <div> <form> {renderFields(props.object)} </form> </div> ); } export default GenericForm;
核心逻辑说明
- 抽离独立的递归渲染方法,支持任意层级的嵌套对象遍历
- 嵌套字段自动拼接完整路径作为
id和name,避免字段冲突,同时符合表单嵌套字段的通用命名规范 - 嵌套对象的隐藏输入框默认值做了序列化处理,保证值存储正确
- 赋值逻辑按路径逐层查找目标属性,无论嵌套多少层都可以正确修改原对象对应属性
- 嵌套层级默认添加左侧缩进,视觉上可以明确区分属性所属层级
内容的提问来源于stack exchange,提问作者robskaar
相关产品推荐
相关产品推荐

