Skip to content

Commit 34785c5

Browse files
committed
setFieldsValue also update Fields status
1 parent f16b564 commit 34785c5

File tree

4 files changed

+78
-8
lines changed

4 files changed

+78
-8
lines changed

src/Field.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,18 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
163163
const prevValue = this.getValue(prevStore);
164164
const curValue = this.getValue();
165165

166+
const namePathMatch = namePathList && containsNamePath(namePathList, namePath);
167+
168+
// `setFieldsValue` is a quick access to update related status
169+
if (info.type === 'valueUpdate' && info.source === 'external' && prevValue !== curValue) {
170+
this.touched = true;
171+
this.validatePromise = null;
172+
this.errors = [];
173+
}
174+
166175
switch (info.type) {
167176
case 'reset':
168-
if (!namePathList || (namePathList && containsNamePath(namePathList, namePath))) {
177+
if (!namePathList || namePathMatch) {
169178
// Clean up state
170179
this.touched = false;
171180
this.validatePromise = null;
@@ -181,7 +190,7 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
181190
break;
182191

183192
case 'setField': {
184-
if (namePathList && containsNamePath(namePathList, namePath)) {
193+
if (namePathMatch) {
185194
const { data } = info;
186195
if ('touched' in data) {
187196
this.touched = data.touched;
@@ -205,7 +214,7 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
205214
*/
206215
const dependencyList = dependencies.map(getNamePath);
207216
if (
208-
(namePathList && containsNamePath(namePathList, namePath)) ||
217+
namePathMatch ||
209218
dependencyList.some(dependency => containsNamePath(info.relatedFields, dependency))
210219
) {
211220
this.reRender();
@@ -222,12 +231,12 @@ class Field extends React.Component<FieldProps, FieldState> implements FieldEnti
222231
* - else to check if value changed
223232
*/
224233
if (
225-
(namePathList && containsNamePath(namePathList, namePath)) ||
234+
namePathMatch ||
226235
dependencies.some(dependency =>
227236
containsNamePath(namePathList, getNamePath(dependency)),
228237
) ||
229238
(typeof shouldUpdate === 'function'
230-
? shouldUpdate(prevStore, values, info)
239+
? shouldUpdate(prevStore, values, 'source' in info ? { source: info.source } : {})
231240
: prevValue !== curValue)
232241
) {
233242
this.reRender();

src/interface.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,15 @@ export type InternalValidateFields = (
111111
) => Promise<Store>;
112112
export type ValidateFields = (nameList?: NamePath[]) => Promise<Store>;
113113

114+
interface ValueUpdateInfo {
115+
type: 'valueUpdate';
116+
source: 'internal' | 'external';
117+
}
118+
114119
export type NotifyInfo =
120+
| ValueUpdateInfo
115121
| {
116-
type: 'valueUpdate' | 'validateFinish' | 'reset';
117-
source?: 'internal' | 'external';
122+
type: 'validateFinish' | 'reset';
118123
}
119124
| {
120125
type: 'setField';

src/useForm.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ export class FormStore {
369369
this.store = setValues(this.store, store);
370370
}
371371

372-
this.notifyObservers(prevStore, null, { type: 'valueUpdate' });
372+
this.notifyObservers(prevStore, null, { type: 'valueUpdate', source: 'external' });
373373
};
374374

375375
private getDependencyChildrenFields = (rootNamePath: InternalNamePath): InternalNamePath[] => {

tests/index.test.js

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,4 +474,60 @@ describe('Form.Basic', () => {
474474
expect(called1).toBeTruthy();
475475
expect(called2).toBeTruthy();
476476
});
477+
478+
it('setFieldsValue should clean up status', async () => {
479+
let form;
480+
let currentMeta;
481+
482+
const wrapper = mount(
483+
<div>
484+
<Form
485+
ref={instance => {
486+
form = instance;
487+
}}
488+
>
489+
<Field name="normal" rules={[{ validator: () => new Promise(() => {}) }]}>
490+
{(control, meta) => {
491+
currentMeta = meta;
492+
return <Input {...control} />;
493+
}}
494+
</Field>
495+
</Form>
496+
</div>,
497+
);
498+
499+
// Init
500+
expect(form.getFieldValue('normal')).toBe(undefined);
501+
expect(form.isFieldTouched('normal')).toBeFalsy();
502+
expect(form.getFieldError('normal')).toEqual([]);
503+
expect(currentMeta.validating).toBeFalsy();
504+
505+
// Set it
506+
form.setFieldsValue({
507+
normal: 'Light',
508+
});
509+
510+
expect(form.getFieldValue('normal')).toBe('Light');
511+
expect(form.isFieldTouched('normal')).toBeTruthy();
512+
expect(form.getFieldError('normal')).toEqual([]);
513+
expect(currentMeta.validating).toBeFalsy();
514+
515+
// Input it
516+
await changeValue(getField(wrapper), 'Bamboo');
517+
518+
expect(form.getFieldValue('normal')).toBe('Bamboo');
519+
expect(form.isFieldTouched('normal')).toBeTruthy();
520+
expect(form.getFieldError('normal')).toEqual([]);
521+
expect(currentMeta.validating).toBeTruthy();
522+
523+
// Set it again
524+
form.setFieldsValue({
525+
normal: 'Light',
526+
});
527+
528+
expect(form.getFieldValue('normal')).toBe('Light');
529+
expect(form.isFieldTouched('normal')).toBeTruthy();
530+
expect(form.getFieldError('normal')).toEqual([]);
531+
expect(currentMeta.validating).toBeFalsy();
532+
});
477533
});

0 commit comments

Comments
 (0)