mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 21:19:37 +08:00
refactor: Form.Item with pure children will only render once (#21991)
* refactor: Form.Item with pure children will only render once * not skip for real render
This commit is contained in:
parent
76de873d87
commit
9fdb82b7df
@ -21,6 +21,21 @@ type RenderChildren = (form: FormInstance) => React.ReactNode;
|
|||||||
type RcFieldProps = Omit<FieldProps, 'children'>;
|
type RcFieldProps = Omit<FieldProps, 'children'>;
|
||||||
type ChildrenType = React.ReactElement | RenderChildren | React.ReactElement[] | null;
|
type ChildrenType = React.ReactElement | RenderChildren | React.ReactElement[] | null;
|
||||||
|
|
||||||
|
interface MemoInputProps {
|
||||||
|
value: any;
|
||||||
|
update: number;
|
||||||
|
children: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemoInput = React.memo<MemoInputProps>(
|
||||||
|
({ children }) => {
|
||||||
|
return children;
|
||||||
|
},
|
||||||
|
(prev, next) => {
|
||||||
|
return prev.value === next.value && prev.update === next.update;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export interface FormItemProps
|
export interface FormItemProps
|
||||||
extends FormItemLabelProps,
|
extends FormItemLabelProps,
|
||||||
FormItemInputProps,
|
FormItemInputProps,
|
||||||
@ -216,6 +231,10 @@ function FormItem(props: FormItemProps): React.ReactElement {
|
|||||||
return renderLayout(children);
|
return renderLayout(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record for real component render
|
||||||
|
const updateRef = React.useRef(0);
|
||||||
|
updateRef.current += 1;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Field
|
<Field
|
||||||
{...props}
|
{...props}
|
||||||
@ -296,7 +315,14 @@ function FormItem(props: FormItemProps): React.ReactElement {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
childNode = React.cloneElement(children, childProps);
|
childNode = (
|
||||||
|
<MemoInput
|
||||||
|
value={mergedControl[props.valuePropName || 'value']}
|
||||||
|
update={updateRef.current}
|
||||||
|
>
|
||||||
|
{React.cloneElement(children, childProps)}
|
||||||
|
</MemoInput>
|
||||||
|
);
|
||||||
} else if (isRenderProps && shouldUpdate && !hasName) {
|
} else if (isRenderProps && shouldUpdate && !hasName) {
|
||||||
childNode = (children as RenderChildren)(context);
|
childNode = (children as RenderChildren)(context);
|
||||||
} else {
|
} else {
|
||||||
|
@ -621,4 +621,35 @@ describe('Form', () => {
|
|||||||
}
|
}
|
||||||
expect(instances.size).toEqual(1);
|
expect(instances.size).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('avoid re-render', async () => {
|
||||||
|
let renderTimes = 0;
|
||||||
|
|
||||||
|
const MyInput = ({ value = '', ...props }) => {
|
||||||
|
renderTimes += 1;
|
||||||
|
return <input value={value} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Demo = () => (
|
||||||
|
<Form>
|
||||||
|
<Form.Item name="username" rules={[{ required: true }]}>
|
||||||
|
<MyInput />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrapper = mount(<Demo />);
|
||||||
|
renderTimes = 0;
|
||||||
|
|
||||||
|
wrapper.find('input').simulate('change', {
|
||||||
|
target: {
|
||||||
|
value: 'a',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await delay();
|
||||||
|
|
||||||
|
expect(renderTimes).toEqual(1);
|
||||||
|
expect(wrapper.find('input').props().value).toEqual('a');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user