Skip to content

Commit b226ad6

Browse files
authored
fix: shouldUpdate should also work on setFields (#69)
* init test case * fix should update by `setFields` * update package.json
1 parent c465860 commit b226ad6

File tree

3 files changed

+116
-41
lines changed

3 files changed

+116
-41
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
"name": "rc-field-form",
33
"version": "0.0.0-alpha.30",
44
"description": "React Form Component",
5+
"engines": {
6+
"node": ">=8.x"
7+
},
58
"keywords": [
69
"react",
710
"react-component",

src/Field.tsx

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,32 @@ import {
2626
getValue,
2727
} from './utils/valueUtil';
2828

29+
export type ShouldUpdate =
30+
| true
31+
| ((
32+
prevValues: Store,
33+
nextValues: Store,
34+
info: { source?: string },
35+
) => boolean);
36+
37+
function requireUpdate(
38+
shouldUpdate: ShouldUpdate,
39+
prev: StoreValue,
40+
next: StoreValue,
41+
prevValue: StoreValue,
42+
nextValue: StoreValue,
43+
info: NotifyInfo,
44+
): boolean {
45+
if (typeof shouldUpdate === 'function') {
46+
return shouldUpdate(
47+
prev,
48+
next,
49+
'source' in info ? { source: info.source } : {},
50+
);
51+
}
52+
return prevValue !== nextValue;
53+
}
54+
2955
interface ChildProps {
3056
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3157
[name: string]: any;
@@ -53,13 +79,7 @@ export interface FieldProps {
5379
allValues: Store,
5480
) => StoreValue;
5581
rules?: Rule[];
56-
shouldUpdate?:
57-
| true
58-
| ((
59-
prevValues: Store,
60-
nextValues: Store,
61-
info: { source?: string },
62-
) => boolean);
82+
shouldUpdate?: ShouldUpdate;
6383
trigger?: string;
6484
validateTrigger?: string | string[] | false;
6585
valuePropName?: string;
@@ -219,6 +239,23 @@ class Field extends React.Component<FieldProps, FieldState>
219239
this.reRender();
220240
return;
221241
}
242+
243+
// Handle update by `setField` with `shouldUpdate`
244+
if (
245+
shouldUpdate &&
246+
!namePath.length &&
247+
requireUpdate(
248+
shouldUpdate,
249+
prevStore,
250+
values,
251+
prevValue,
252+
curValue,
253+
info,
254+
)
255+
) {
256+
this.reRender();
257+
return;
258+
}
222259
break;
223260
}
224261

@@ -251,13 +288,14 @@ class Field extends React.Component<FieldProps, FieldState>
251288
dependencies.some(dependency =>
252289
containsNamePath(namePathList, getNamePath(dependency)),
253290
) ||
254-
(typeof shouldUpdate === 'function'
255-
? shouldUpdate(
256-
prevStore,
257-
values,
258-
'source' in info ? { source: info.source } : {},
259-
)
260-
: prevValue !== curValue)
291+
requireUpdate(
292+
shouldUpdate,
293+
prevStore,
294+
values,
295+
prevValue,
296+
curValue,
297+
info,
298+
)
261299
) {
262300
this.reRender();
263301
return;

tests/index.test.js

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -476,35 +476,69 @@ describe('Form.Basic', () => {
476476
expect(hasError).toBeTruthy();
477477
});
478478

479-
it('setFields', () => {
480-
let form;
481-
const wrapper = mount(
482-
<div>
483-
<Form
484-
ref={instance => {
485-
form = instance;
486-
}}
487-
>
488-
<InfoField name="username">
489-
<Input />
490-
</InfoField>
491-
</Form>
492-
</div>,
493-
);
479+
describe('setFields', () => {
480+
it('should work', () => {
481+
let form;
482+
const wrapper = mount(
483+
<div>
484+
<Form
485+
ref={instance => {
486+
form = instance;
487+
}}
488+
>
489+
<InfoField name="username">
490+
<Input />
491+
</InfoField>
492+
</Form>
493+
</div>,
494+
);
494495

495-
form.setFields([
496-
{
497-
name: 'username',
498-
touched: false,
499-
validating: true,
500-
errors: ['Set It!'],
501-
},
502-
]);
503-
wrapper.update();
496+
form.setFields([
497+
{
498+
name: 'username',
499+
touched: false,
500+
validating: true,
501+
errors: ['Set It!'],
502+
},
503+
]);
504+
wrapper.update();
504505

505-
matchError(wrapper, 'Set It!');
506-
expect(wrapper.find('.validating').length).toBeTruthy();
507-
expect(form.isFieldsTouched()).toBeFalsy();
506+
matchError(wrapper, 'Set It!');
507+
expect(wrapper.find('.validating').length).toBeTruthy();
508+
expect(form.isFieldsTouched()).toBeFalsy();
509+
});
510+
511+
it('should trigger by setField', () => {
512+
const triggerUpdate = jest.fn();
513+
const formRef = React.createRef();
514+
515+
const wrapper = mount(
516+
<div>
517+
<Form ref={formRef}>
518+
<Field shouldUpdate={(prev, next) => prev.value !== next.value}>
519+
{() => {
520+
triggerUpdate();
521+
return <input />;
522+
}}
523+
</Field>
524+
</Form>
525+
</div>,
526+
);
527+
wrapper.update();
528+
triggerUpdate.mockReset();
529+
530+
// Not trigger render
531+
formRef.current.setFields([
532+
{ name: 'others', value: 'no need to update' },
533+
]);
534+
wrapper.update();
535+
expect(triggerUpdate).not.toHaveBeenCalled();
536+
537+
// Trigger render
538+
formRef.current.setFields([{ name: 'value', value: 'should update' }]);
539+
wrapper.update();
540+
expect(triggerUpdate).toHaveBeenCalled();
541+
});
508542
});
509543

510544
it('render props get meta', () => {

0 commit comments

Comments
 (0)