Antd Form.Item 中包裹组件 onChange 穿透
问题描述
在使用antd Form.Item的时候 嵌入Input这种表单组件,会默认在内部注入onChange、value等props
<Form>
<Form.Item name="name">
<Input />
</Form.Item>
</Form>
上面可以看到 Input 组件并没有用 onChange 和 value 来进行数据处理,所有的数据管理都由整个 Form 组件进行内部整合,整体看起来很比较整洁,没有额外的代码干扰
实现原理
探究疑问
- Input 组件作为一个 children 传递,如果做到给他传递 props 呢?
- Input 使用的时候加上了 onChange 等属性的时候,Form.Item 如何给Input 这个 children 传递 onChange 呢?不会被覆盖掉吗?
原理
问题 1
在 React 中存在一个 API cloneElement 方法,使用该方法可以 clone 一个新的 React 元素,同时可以传递 props。
代码示例
import { cloneElement } from "react";
const clonedElement = cloneElement(
<Row title="Cabbage">Hello</Row>,
{ isHighlighted: true },
"Goodbye"
);
console.log(clonedElement);
在 Form.Item 组件的源码中也可以看到是以该 API 进行处理 props 的 代码示例
<MemoInput
control={mergedControl}
update={mergedChildren}
childProps={watchingChildProps}
>
{cloneElement(mergedChildren, childProps)}
</MemoInput>
问题 2
在 Form.Item 源码中,构建了一个统一的 onChange 方法,将 Form.Item 内部传递的 onChange 方法,和 Input 直接传递的 onChange 方法,归于该方法里面统一调用。避免方法被覆盖掉倒是 Input 自身传入的 onChange 方法失效。
代码示例
// trigger 是描述 表单组件的 触发方法的 例如 onChange这种
const triggers = new Set<string>([
...toArray(trigger),
...toArray(mergedValidateTrigger),
]);
triggers.forEach((eventName) => {
childProps[eventName] = (...args: any[]) => {
mergedControl[eventName]?.(...args);
mergedChildren.props[eventName]?.(...args);
};
});
如上所述,我们可以在构建一些自定义的表单组件的时候,可以根据这一特性,去兼容 antd 的 Form 表单组件,减少复杂的表单数据管理操作。