近期的痛苦都是表单带来的!
最近的一个需求涉及到如何显示表单叠加子字段,叫ai给我写又是表单嵌套,看着密密麻麻的表单项和setget,我有点犹豫,但是又不知如何是好,于是乎,我就去冲浪看看,有什么解决办法: blog.csdn.net/weixin_4709…
还真就被我找到了,其实我可以直接搜组件文档的,但是因为antd公司的网络总是加载不出来,所以我就退而求其次,而且全网搜或许效果更好?
所以,今天我又新认识了一个叫做Form.List的东西,我把这篇文档交给ai,等它改的差不多了,现在我又通读了一下整体官方文档: ant-design.antgroup.com/components/…
现在我从原来的form.item全是嵌套,到现在使用Form.List然后在里面写Form.Item,
<Form.List name={name} initialValue={initialValue}>
{(fields, { add, remove }) => (
<div>
{fields.map(({ key, name: fieldName, fieldKey, ...restField }) => {
const currentid = form.getFieldValue([fieldName, 'id']);
return (
<div key={key}>
<Space style={{ display: 'flex' }} align='baseline'>
<Form.Item
{...restField}
name={[fieldName, 'id']}
fieldKey={[fieldKey || 0, 'id']}
>
</Form.Item>
<Form.Item
{...restField}
name={[fieldName, 'planId']}
fieldKey={[fieldKey || 0, 'planId']}
>
</Form.Item>
<Form.Item
{...restField}
name={[fieldName, 'branch']}
fieldKey={[fieldKey || 0, 'branch']}
>
</Form.Item>
<MinusCircleOutlined
remove(fieldName);
}}
/>
</Space>
</div>
);
})}
<Form.Item style={{marginBottom:0}}>
<Button
type='dashed'
onClick={() => add()}
block
icon={<PlusOutlined />}
>
</Button>
</Form.Item>
</div>
)}
</Form.List>
这是我刚开始的代码,其实ai对于开源组件库根本就不是那么的熟悉,所以他需要将有关文档读一遍,可以写得更好,在我自己范围api文档的的过程中,我发现,ai的有些写法有点多余,所以我把文档交给他,让他去读并且改进,于是,就有了下面的代码,很明显,这一次,精简的多!
- 它删除了我很多嵌套的div,简化了dom结构,
- 并且删除了一些不必要的get获取,同时,帮我把冗余的change函数放到了上面用callback缓存;
- 去掉了...restField,并且给我详细分清楚了这些个name是怎么回事:
第一个name,是一个字符串或者数组,表示的是在表格里面这个数组的字段,第二个fieldName,表示的是在这个数组里面的索引名,所以就有两个区分:第一个,如果你想要传递给表单一个什么样的字段集合;这样去看,上面的代码就都合理了,这是现在的代码:
<Form.List name={name} initialValue={initialValue}>
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name: fieldName }) => {
const currentid = form.getFieldValue([...name, fieldName, 'id']);
return (
<Space key={key} style={{ display: 'flex' }} align='baseline'>
<Form.Item name={[fieldName, 'id']}>
</Form.Item>
<Form.Item name={[fieldName, 'planId']}>
</Form.Item>
<Form.Item name={[fieldName, 'branch']}>
</Form.Item>
<MinusCircleOutlined onClick={() => remove(fieldName)} />
</Space>
);
})}
<Form.Item style={{ marginBottom: 0 }}>
<Button type='dashed' onClick={() => add()} block icon={<PlusOutlined />}>
</Button>
</Form.Item>
</>
)}
</Form.List>
其实这里的很多change都没有显示出来和细节,因为涉及到业务代码,但是在结构上也确实变化了,所以主要显示结构变化;
精简之后,我开始考虑一个问题,那就是我在刚开始的时候有一个获取id的字段,这个时候变化id的获取,后续字段也会随之变化:因为刷新的缘故renderFormItem,所以这个问题是解决了,那么为什么renderForm执行两次,可以认为是严格模式,但是组件只执行一次,感觉是因为组件有合并刷新?
1. 严格模式的「双重重执行」特性
React 严格模式(<React.StrictMode>)会刻意双重执行某些函数(如组件函数、useEffect 回调、状态更新函数等),但这仅限于「开发环境」,目的是:
- 检测副作用(如未清理的定时器、未取消的订阅等)
- 提前掘不符合 React 最佳实践的代码(如使用过时的 API)
这种双重执行是模拟性的,不会会真正影响最终渲染结果(第二次执行的结果会被丢弃),也不会触发真实的 DOM 更新。因此你会看到函数执行了两次,但组件最终只渲染一次。
2. renderForm 与组件渲染的区别
renderForm 是 antd Form 组件内部用于构建表单结构的函数(类似配置项的处理函数),它的执行时机早于组件实际渲染:
- 当表单初始化或配置变更时,
renderForm会被调用以解析表单配置(如字段规则、布局等) - 由于它是「配置处理函数」而非「组件渲染函数」,严格模式的双重执行会直接作用于它(执行两次)
而组件的「渲染」指的是生成 DOM 结构的过程,React 会确保即使函数被执行两次,最终也只会产生一次有效的 DOM 渲染,因此你看到组件只执行一次。