diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx index 24d7e6dfbb..1971080706 100644 --- a/components/form/FormItem.tsx +++ b/components/form/FormItem.tsx @@ -21,6 +21,21 @@ type RenderChildren = (form: FormInstance) => React.ReactNode; type RcFieldProps = Omit; type ChildrenType = React.ReactElement | RenderChildren | React.ReactElement[] | null; +interface MemoInputProps { + value: any; + update: number; + children: any; +} + +const MemoInput = React.memo( + ({ children }) => { + return children; + }, + (prev, next) => { + return prev.value === next.value && prev.update === next.update; + }, +); + export interface FormItemProps extends FormItemLabelProps, FormItemInputProps, @@ -216,6 +231,10 @@ function FormItem(props: FormItemProps): React.ReactElement { return renderLayout(children); } + // Record for real component render + const updateRef = React.useRef(0); + updateRef.current += 1; + return ( + {React.cloneElement(children, childProps)} + + ); } else if (isRenderProps && shouldUpdate && !hasName) { childNode = (children as RenderChildren)(context); } else { diff --git a/components/form/__tests__/index.test.js b/components/form/__tests__/index.test.js index 186ec5a194..a34ca18087 100644 --- a/components/form/__tests__/index.test.js +++ b/components/form/__tests__/index.test.js @@ -621,4 +621,35 @@ describe('Form', () => { } expect(instances.size).toEqual(1); }); + + it('avoid re-render', async () => { + let renderTimes = 0; + + const MyInput = ({ value = '', ...props }) => { + renderTimes += 1; + return ; + }; + + const Demo = () => ( +
+ + + +
+ ); + + const wrapper = mount(); + renderTimes = 0; + + wrapper.find('input').simulate('change', { + target: { + value: 'a', + }, + }); + + await delay(); + + expect(renderTimes).toEqual(1); + expect(wrapper.find('input').props().value).toEqual('a'); + }); });