From cd43748c61c26b26386ffd7796cd802d5c41dc10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=B8=85?= Date: Thu, 16 Sep 2021 00:43:41 +0800 Subject: [PATCH] fix(form): fix the problem of multiple calls (#3676) * fix(form): fix the problem of multiple calls * add more test * fix test --- packages/form/src/BaseForm/createField.tsx | 5 +- .../form/src/components/DatePicker/index.tsx | 3 + packages/form/src/components/Field/index.tsx | 8 +-- .../form/src/components/FieldSet/index.tsx | 59 ++++++++++++------- .../form/src/components/FormItem/index.tsx | 14 +++-- packages/form/src/components/Radio/index.tsx | 4 ++ packages/form/src/components/Rate/index.tsx | 8 +-- .../form/src/components/SchemaForm/index.tsx | 2 +- packages/form/src/components/Select/index.tsx | 4 ++ packages/form/src/components/Text/index.tsx | 12 ++-- .../form/src/components/TextArea/index.tsx | 8 +-- tests/form/__snapshots__/demo.test.ts.snap | 12 ++-- tests/form/fieldSet.test.tsx | 59 +++++++++++++++++++ tests/form/formitem.test.tsx | 2 +- 14 files changed, 139 insertions(+), 61 deletions(-) diff --git a/packages/form/src/BaseForm/createField.tsx b/packages/form/src/BaseForm/createField.tsx index 3b0f6b62672a..6be62125ada5 100644 --- a/packages/form/src/BaseForm/createField.tsx +++ b/packages/form/src/BaseForm/createField.tsx @@ -180,7 +180,10 @@ function createField

( ); }; - + // 标记是否是 proform 的组件 + // @ts-ignore + // eslint-disable-next-line no-param-reassign + FieldWithContext.displayName = 'ProFormComponent'; return FieldWithContext as ProFormComponent; } diff --git a/packages/form/src/components/DatePicker/index.tsx b/packages/form/src/components/DatePicker/index.tsx index 82c51c1fce50..5c430b098cf1 100644 --- a/packages/form/src/components/DatePicker/index.tsx +++ b/packages/form/src/components/DatePicker/index.tsx @@ -15,5 +15,8 @@ ExportComponent.Week = ProFormDatePickerWeek; ExportComponent.Month = ProFormDatePickerMonth; ExportComponent.Quarter = ProFormDatePickerQuarter; ExportComponent.Year = ProFormDatePickerYear; +// @ts-ignore +// eslint-disable-next-line no-param-reassign +ExportComponent.displayName = 'ProFormComponent'; export default ExportComponent; diff --git a/packages/form/src/components/Field/index.tsx b/packages/form/src/components/Field/index.tsx index 8f45a62dcbee..12676351793e 100644 --- a/packages/form/src/components/Field/index.tsx +++ b/packages/form/src/components/Field/index.tsx @@ -73,13 +73,7 @@ const ProFormField: React.FC< render={render as any} renderFormItem={renderFormItem as any} valueType={(valueType as 'text') || 'text'} - fieldProps={{ - ...fieldProps, - onChange: (...restParams: any) => { - (fieldProps?.onChange as any)?.(...restParams); - onChange?.(...restParams); - }, - }} + fieldProps={fieldProps} valueEnum={runFunction(valueEnum)} {...proFieldProps} {...restProps} diff --git a/packages/form/src/components/FieldSet/index.tsx b/packages/form/src/components/FieldSet/index.tsx index 3df52ffd9fc8..a5bed683186a 100644 --- a/packages/form/src/components/FieldSet/index.tsx +++ b/packages/form/src/components/FieldSet/index.tsx @@ -32,6 +32,7 @@ const FieldSet: React.FC = ({ value = [], valuePropName, onChange, + fieldProps, space, type = 'space', }) => { @@ -39,6 +40,7 @@ const FieldSet: React.FC = ({ const newValues = [...value]; newValues[index] = defaultGetValueFromEvent(valuePropName || 'value', fileValue); onChange?.(newValues); + fieldProps?.onChange?.(newValues); }; let itemIndex = -1; @@ -46,24 +48,34 @@ const FieldSet: React.FC = ({ if (React.isValidElement(item)) { itemIndex += 1; const index = itemIndex; - return React.cloneElement(item, { - key: index, - ignoreFormItem: true, - ...((item.props as any) || {}), - fieldProps: { - ...(item?.props as any)?.fieldProps, - onChange: (...restParams: any) => { - (item.props as any)?.fieldProps?.onChange?.(...restParams); - (item.props as any)?.onChange?.(...restParams); - fieldSetOnChange(restParams[0], index); - }, - }, - value: value[index], - onChange: (itemValue: any) => { - fieldSetOnChange(itemValue, index); - (item as any).props.onChange?.(itemValue); - }, - }); + const isProFromItem = + // @ts-ignore + item?.type?.displayName === 'ProFormComponent' || item?.props?.readonly; + const forkProps = isProFromItem + ? { + key: index, + ignoreFormItem: true, + ...((item.props as any) || {}), + // 如果不是我们自定义的组件 fieldProps 无法识别 + fieldProps: { + ...(item?.props as any)?.fieldProps, + onChange: (...restParams: any) => { + fieldSetOnChange(restParams[0], index); + }, + }, + value: value[index], + onChange: undefined, + } + : { + key: index, + ...((item.props as any) || {}), + value: value[index], + onChange: (itemValue: any) => { + fieldSetOnChange(itemValue, index); + (item as any).props.onChange?.(itemValue); + }, + }; + return React.cloneElement(item, forkProps); } return item; }); @@ -72,7 +84,7 @@ const FieldSet: React.FC = ({ /** Input.Group 需要配置 compact */ const typeProps = { ...(type === 'group' ? { compact: true } : {}) }; return ( - + {list} ); @@ -82,7 +94,14 @@ const ProFormFieldSet: React.FC = React.fo ({ children, space, valuePropName, ...rest }, ref) => { useImperativeHandle(ref, () => {}, []); return ( -

+
{children}
); diff --git a/packages/form/src/components/FormItem/index.tsx b/packages/form/src/components/FormItem/index.tsx index 16cec4367dce..344efb92b4ee 100644 --- a/packages/form/src/components/FormItem/index.tsx +++ b/packages/form/src/components/FormItem/index.tsx @@ -26,6 +26,7 @@ const WithValueFomFiledProps: React.FC> = (formFieldProps) = value, onChange, onBlur, + ignoreFormItem, valuePropName = 'value', ...restProps } = formFieldProps; @@ -58,16 +59,20 @@ const WithValueFomFiledProps: React.FC> = (formFieldProps) = if (!React.isValidElement(filedChildren)) return filedChildren as JSX.Element; + const finalChange = fieldProps + ? undefined + : (...restParams: any[]) => { + onChange?.(...restParams); + filedChildren?.props?.onChange?.(...restParams); + }; + return React.cloneElement( filedChildren, omitUndefined({ ...restProps, value, ...filedChildren.props, - onChange: (...restParams: any[]) => { - onChange?.(...restParams); - filedChildren?.props?.onChange?.(...restParams); - }, + onChange: finalChange, fieldProps, }), ); @@ -215,6 +220,7 @@ const ProFormItem: React.FC = (props) => { if (ignoreFormItem) { return <>{lightDom}; } + return ( {lightDom} diff --git a/packages/form/src/components/Radio/index.tsx b/packages/form/src/components/Radio/index.tsx index e64a20b37950..8d82d3127522 100644 --- a/packages/form/src/components/Radio/index.tsx +++ b/packages/form/src/components/Radio/index.tsx @@ -67,4 +67,8 @@ WrappedProFormRadio.Group = RadioGroup; WrappedProFormRadio.Button = Radio.Button; +// @ts-ignore +// eslint-disable-next-line no-param-reassign +WrappedProFormRadio.displayName = 'ProFormComponent'; + export default WrappedProFormRadio; diff --git a/packages/form/src/components/Rate/index.tsx b/packages/form/src/components/Rate/index.tsx index a16444287548..d59a39629f0b 100644 --- a/packages/form/src/components/Rate/index.tsx +++ b/packages/form/src/components/Rate/index.tsx @@ -15,13 +15,7 @@ const ProFormRate: React.ForwardRefRenderFunction { - (fieldProps?.onChange as any)?.(...restParams); - (rest as any)?.onChange?.(...restParams); - }, - }} + fieldProps={fieldProps} ref={ref} proFieldProps={proFieldProps} filedConfig={{ diff --git a/packages/form/src/components/SchemaForm/index.tsx b/packages/form/src/components/SchemaForm/index.tsx index 0d3a99fceb91..c8a7652177ae 100644 --- a/packages/form/src/components/SchemaForm/index.tsx +++ b/packages/form/src/components/SchemaForm/index.tsx @@ -235,7 +235,7 @@ function BetaSchemaForm(props: FormSchema) /** 分割线 */ if (item.valueType === 'divider') { - return ; + return ; } /** 公用的 类型 props */ diff --git a/packages/form/src/components/Select/index.tsx b/packages/form/src/components/Select/index.tsx index 5c0fde4f6925..c8331766cf7d 100644 --- a/packages/form/src/components/Select/index.tsx +++ b/packages/form/src/components/Select/index.tsx @@ -130,4 +130,8 @@ const WrappedProFormSelect = ProFormSelect as (( WrappedProFormSelect.SearchSelect = ProFormSearchSelect; +// @ts-ignore +// eslint-disable-next-line no-param-reassign +WrappedProFormSelect.displayName = 'ProFormComponent'; + export default WrappedProFormSelect; diff --git a/packages/form/src/components/Text/index.tsx b/packages/form/src/components/Text/index.tsx index 3e1263a5e29a..e96a2654f529 100644 --- a/packages/form/src/components/Text/index.tsx +++ b/packages/form/src/components/Text/index.tsx @@ -19,13 +19,7 @@ const ProFormText: React.FC> = ({ { - (fieldProps?.onChange as any)?.(...restParams); - (rest as any)?.onChange?.(...restParams); - }, - }} + fieldProps={fieldProps} filedConfig={ { valueType, @@ -64,4 +58,8 @@ const WrappedProFormText: typeof ProFormText & { WrappedProFormText.Password = Password; +// @ts-ignore +// eslint-disable-next-line no-param-reassign +WrappedProFormText.displayName = 'ProFormComponent'; + export default WrappedProFormText; diff --git a/packages/form/src/components/TextArea/index.tsx b/packages/form/src/components/TextArea/index.tsx index d21be0bac66f..4e407c9c2d24 100644 --- a/packages/form/src/components/TextArea/index.tsx +++ b/packages/form/src/components/TextArea/index.tsx @@ -17,13 +17,7 @@ const ProFormTextArea: React.ForwardRefRenderFunction { - (fieldProps?.onChange as any)?.(...restParams); - (rest as any)?.onChange?.(...restParams); - }, - }} + fieldProps={fieldProps} proFieldProps={proFieldProps} {...rest} /> diff --git a/tests/form/__snapshots__/demo.test.ts.snap b/tests/form/__snapshots__/demo.test.ts.snap index 39db0e7d8e41..aece871a4721 100644 --- a/tests/form/__snapshots__/demo.test.ts.snap +++ b/tests/form/__snapshots__/demo.test.ts.snap @@ -2780,7 +2780,7 @@ exports[`form demos 📸 renders ./packages/form/src/components/FieldSet/demos/c class="ant-form-item-control-input-content" >
{ it('😊 ProFormFieldSet onChange', async () => { @@ -45,7 +46,65 @@ describe('ProFormFieldSet', () => { }); await waitForComponentToPaint(html); expect(valueFn).toBeCalledWith(['111']); + expect(valueFn).toBeCalledTimes(1); + act(() => { + html.find('textarea#filedSet3').simulate('change', { + target: { + value: '333', + }, + }); + }); + await waitForComponentToPaint(html); + expect(valueFn).toBeCalledWith(['111', undefined, '333']); + + act(() => { + html.find('li > div').at(1).simulate('click'); + }); + expect(valueFn).toBeCalledWith(['111', 2, '333']); + await waitForComponentToPaint(html); + + await waitForComponentToPaint(html, 200); + + act(() => { + html.find('button.ant-btn.ant-btn-primary').simulate('click'); + }); + await waitForComponentToPaint(html, 200); + + expect(fn).toBeCalledWith(['111', 2, '333']); + html.unmount(); + }); + + it('😊 ProFormFieldSet support Input onChange', async () => { + const fn = jest.fn(); + const valueFn = jest.fn(); + const html = mount( + fn(values.list)} + onValuesChange={(value) => valueFn(value.list)} + > + + + + + + , + ); + act(() => { + html.find('input#filedSet1').simulate('change', { + target: { + value: '111', + }, + }); + }); + await waitForComponentToPaint(html); + expect(valueFn).toBeCalledWith(['111']); + expect(valueFn).toBeCalledTimes(1); act(() => { html.find('textarea#filedSet3').simulate('change', { target: { diff --git a/tests/form/formitem.test.tsx b/tests/form/formitem.test.tsx index fd9777dcfc91..cf023168e6df 100644 --- a/tests/form/formitem.test.tsx +++ b/tests/form/formitem.test.tsx @@ -37,7 +37,7 @@ describe('ProForm.Item', () => { expect(onBlur).toBeCalledTimes(1); }); - it('📦 ProForm.Item supprot onChange', async () => { + it('📦 ProForm.Item supports onChange', async () => { const onChange = jest.fn(); const onValuesChange = jest.fn(); const wrapper = mount<{ navTheme: string }>(