Skip to content

Commit 437f3c0

Browse files
authored
fix: onMetaChange trigger when meta not changed (#604)
* test: test driven * fix: meta loop call
1 parent 18c4e0b commit 437f3c0

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

src/Field.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import toChildrenArray from 'rc-util/lib/Children/toArray';
22
import warning from 'rc-util/lib/warning';
3+
import isEqual from 'rc-util/lib/isEqual';
34
import * as React from 'react';
45
import type {
56
FieldEntity,
@@ -54,6 +55,8 @@ interface ChildProps {
5455
[name: string]: any;
5556
}
5657

58+
export type MetaEvent = Meta & { destroy?: boolean };
59+
5760
export interface InternalFieldProps<Values = any> {
5861
children?:
5962
| React.ReactElement
@@ -77,7 +80,7 @@ export interface InternalFieldProps<Values = any> {
7780
messageVariables?: Record<string, string>;
7881
initialValue?: any;
7982
onReset?: () => void;
80-
onMetaChange?: (meta: Meta & { destroy?: boolean }) => void;
83+
onMetaChange?: (meta: MetaEvent) => void;
8184
preserve?: boolean;
8285

8386
/** @private Passed by Form.List props. Do not use since it will break by path check. */
@@ -221,10 +224,23 @@ class Field extends React.Component<InternalFieldProps, FieldState> implements F
221224
}));
222225
};
223226

227+
// Event should only trigger when meta changed
228+
private metaCache: MetaEvent = null;
229+
224230
public triggerMetaEvent = (destroy?: boolean) => {
225231
const { onMetaChange } = this.props;
226232

227-
onMetaChange?.({ ...this.getMeta(), destroy });
233+
if (onMetaChange) {
234+
const meta = { ...this.getMeta(), destroy };
235+
236+
if (!isEqual(this.metaCache, meta)) {
237+
onMetaChange(meta);
238+
}
239+
240+
this.metaCache = meta;
241+
} else {
242+
this.metaCache = null;
243+
}
228244
};
229245

230246
// ========================= Field Entity Interfaces =========================

tests/index.test.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,4 +838,29 @@ describe('Form.Basic', () => {
838838
Array.from(container.querySelectorAll<HTMLInputElement>('input')).map(input => input?.value),
839839
).toEqual(['bamboo', 'tiny', 'light', 'match']);
840840
});
841+
842+
it('onMetaChange should only trigger when meta changed', () => {
843+
const onMetaChange = jest.fn();
844+
const formRef = React.createRef<FormInstance>();
845+
846+
const Demo: React.FC = () => (
847+
<Form ref={formRef}>
848+
<Field onMetaChange={onMetaChange} shouldUpdate={() => false}>
849+
{() => null}
850+
</Field>
851+
</Form>
852+
);
853+
854+
render(<Demo />);
855+
856+
formRef.current?.setFieldsValue({});
857+
onMetaChange.mockReset();
858+
859+
// Re-render should not trigger `onMetaChange`
860+
for (let i = 0; i < 10; i += 1) {
861+
formRef.current?.setFieldsValue({});
862+
}
863+
864+
expect(onMetaChange).toHaveBeenCalledTimes(0);
865+
});
841866
});

0 commit comments

Comments
 (0)