Skip to content

Commit bacc740

Browse files
authored
warning if not regist form (#63)
1 parent c677a9e commit bacc740

File tree

2 files changed

+101
-14
lines changed

2 files changed

+101
-14
lines changed

src/useForm.ts

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ interface ValidateAction {
4646
export type ReducerAction = UpdateAction | ValidateAction;
4747

4848
export class FormStore {
49+
private formHooked: boolean = false;
50+
4951
private forceRootUpdate: () => void;
5052

5153
private subscribable: boolean = true;
@@ -87,6 +89,8 @@ export class FormStore {
8789
// ======================== Internal Hooks ========================
8890
private getInternalHooks = (key: string): InternalHooks | null => {
8991
if (key === HOOK_MARK) {
92+
this.formHooked = true;
93+
9094
return {
9195
dispatch: this.dispatch,
9296
registerField: this.registerField,
@@ -98,7 +102,10 @@ export class FormStore {
98102
};
99103
}
100104

101-
warning(false, '`getInternalHooks` is internal usage. Should not call directly.');
105+
warning(
106+
false,
107+
'`getInternalHooks` is internal usage. Should not call directly.',
108+
);
102109
return null;
103110
};
104111

@@ -116,7 +123,8 @@ export class FormStore {
116123
}
117124
};
118125

119-
private getInitialValue = (namePath: InternalNamePath) => getValue(this.initialValues, namePath);
126+
private getInitialValue = (namePath: InternalNamePath) =>
127+
getValue(this.initialValues, namePath);
120128

121129
private setCallbacks = (callbacks: Callbacks) => {
122130
this.callbacks = callbacks;
@@ -126,6 +134,15 @@ export class FormStore {
126134
this.validateMessages = validateMessages;
127135
};
128136

137+
private warningUnhooked = () => {
138+
if (process.env.NODE_ENV !== 'production' && !this.formHooked) {
139+
warning(
140+
false,
141+
'Instance created by `useForm` is not connect to any Form element. Forget to pass `form` prop?',
142+
);
143+
}
144+
};
145+
129146
// ============================ Fields ============================
130147
/**
131148
* Get registered field entities.
@@ -149,6 +166,8 @@ export class FormStore {
149166
};
150167

151168
private getFieldsValue = (nameList?: NamePath[]) => {
169+
this.warningUnhooked();
170+
152171
if (!nameList) {
153172
return this.store;
154173
}
@@ -157,11 +176,15 @@ export class FormStore {
157176
};
158177

159178
private getFieldValue = (name: NamePath) => {
179+
this.warningUnhooked();
180+
160181
const namePath: InternalNamePath = getNamePath(name);
161182
return getValue(this.store, namePath);
162183
};
163184

164185
private getFieldsError = (nameList?: NamePath[]) => {
186+
this.warningUnhooked();
187+
165188
let fieldEntities = this.getFieldEntities(true);
166189

167190
if (nameList) {
@@ -189,12 +212,16 @@ export class FormStore {
189212
};
190213

191214
private getFieldError = (name: NamePath): string[] => {
215+
this.warningUnhooked();
216+
192217
const namePath = getNamePath(name);
193218
const fieldError = this.getFieldsError([namePath])[0];
194219
return fieldError.errors;
195220
};
196221

197222
private isFieldsTouched = (...args) => {
223+
this.warningUnhooked();
224+
198225
const [arg0, arg1] = args;
199226
let namePathList: InternalNamePath[] | null;
200227
let isAllFieldsTouched = false;
@@ -232,9 +259,14 @@ export class FormStore {
232259
: this.getFieldEntities(true).some(testTouched);
233260
};
234261

235-
private isFieldTouched = (name: NamePath) => this.isFieldsTouched([name]);
262+
private isFieldTouched = (name: NamePath) => {
263+
this.warningUnhooked();
264+
return this.isFieldsTouched([name]);
265+
};
236266

237267
private isFieldsValidating = (nameList?: NamePath[]) => {
268+
this.warningUnhooked();
269+
238270
const fieldEntities = this.getFieldEntities();
239271
if (!nameList) {
240272
return fieldEntities.some(testField => testField.isFieldValidating());
@@ -243,13 +275,22 @@ export class FormStore {
243275
const namePathList: InternalNamePath[] = nameList.map(getNamePath);
244276
return fieldEntities.some(testField => {
245277
const fieldNamePath = testField.getNamePath();
246-
return containsNamePath(namePathList, fieldNamePath) && testField.isFieldValidating();
278+
return (
279+
containsNamePath(namePathList, fieldNamePath) &&
280+
testField.isFieldValidating()
281+
);
247282
});
248283
};
249284

250-
private isFieldValidating = (name: NamePath) => this.isFieldsValidating([name]);
285+
private isFieldValidating = (name: NamePath) => {
286+
this.warningUnhooked();
287+
288+
return this.isFieldsValidating([name]);
289+
};
251290

252291
private resetFields = (nameList?: NamePath[]) => {
292+
this.warningUnhooked();
293+
253294
const prevStore = this.store;
254295
if (!nameList) {
255296
this.store = setValues({}, this.initialValues);
@@ -267,6 +308,8 @@ export class FormStore {
267308
};
268309

269310
private setFields = (fields: FieldData[]) => {
311+
this.warningUnhooked();
312+
270313
const prevStore = this.store;
271314

272315
fields.forEach((fieldData: FieldData) => {
@@ -278,7 +321,10 @@ export class FormStore {
278321
this.store = setValue(this.store, namePath, data.value);
279322
}
280323

281-
this.notifyObservers(prevStore, [namePath], { type: 'setField', data: fieldData });
324+
this.notifyObservers(prevStore, [namePath], {
325+
type: 'setField',
326+
data: fieldData,
327+
});
282328
});
283329
};
284330

@@ -340,7 +386,10 @@ export class FormStore {
340386
const prevStore = this.store;
341387
this.store = setValue(this.store, namePath, value);
342388

343-
this.notifyObservers(prevStore, [namePath], { type: 'valueUpdate', source: 'internal' });
389+
this.notifyObservers(prevStore, [namePath], {
390+
type: 'valueUpdate',
391+
source: 'internal',
392+
});
344393

345394
// Notify dependencies children with parent update
346395
const childrenFields = this.getDependencyChildrenFields(namePath);
@@ -364,16 +413,23 @@ export class FormStore {
364413

365414
// Let all child Field get update.
366415
private setFieldsValue = (store: Store) => {
416+
this.warningUnhooked();
417+
367418
const prevStore = this.store;
368419

369420
if (store) {
370421
this.store = setValues(this.store, store);
371422
}
372423

373-
this.notifyObservers(prevStore, null, { type: 'valueUpdate', source: 'external' });
424+
this.notifyObservers(prevStore, null, {
425+
type: 'valueUpdate',
426+
source: 'external',
427+
});
374428
};
375429

376-
private getDependencyChildrenFields = (rootNamePath: InternalNamePath): InternalNamePath[] => {
430+
private getDependencyChildrenFields = (
431+
rootNamePath: InternalNamePath,
432+
): InternalNamePath[] => {
377433
const children: Set<FieldEntity> = new Set();
378434
const childrenFields: InternalNamePath[] = [];
379435

@@ -431,6 +487,8 @@ export class FormStore {
431487
nameList?: NamePath[],
432488
options?: ValidateOptions,
433489
) => {
490+
this.warningUnhooked();
491+
434492
const provideNameList = !!nameList;
435493
const namePathList: InternalNamePath[] | undefined = provideNameList
436494
? nameList.map(getNamePath)
@@ -486,12 +544,18 @@ export class FormStore {
486544
summaryPromise
487545
.catch(results => results)
488546
.then((results: FieldError[]) => {
489-
const resultNamePathList: InternalNamePath[] = results.map(({ name }) => name);
490-
this.notifyObservers(this.store, resultNamePathList, { type: 'validateFinish' });
547+
const resultNamePathList: InternalNamePath[] = results.map(
548+
({ name }) => name,
549+
);
550+
this.notifyObservers(this.store, resultNamePathList, {
551+
type: 'validateFinish',
552+
});
491553
this.triggerOnFieldsChange(resultNamePathList);
492554
});
493555

494-
const returnPromise: Promise<Store | ValidateErrorEntity | string[]> = summaryPromise
556+
const returnPromise: Promise<
557+
Store | ValidateErrorEntity | string[]
558+
> = summaryPromise
495559
.then(
496560
(): Promise<Store | string[]> => {
497561
if (this.lastValidatePromise === summaryPromise) {
@@ -501,7 +565,9 @@ export class FormStore {
501565
},
502566
)
503567
.catch((results: { name: InternalNamePath; errors: string[] }[]) => {
504-
const errorList = results.filter(result => result && result.errors.length);
568+
const errorList = results.filter(
569+
result => result && result.errors.length,
570+
);
505571
return Promise.reject({
506572
values: this.getFieldsValue(namePathList),
507573
errorFields: errorList,
@@ -517,6 +583,8 @@ export class FormStore {
517583

518584
// ============================ Submit ============================
519585
private submit = () => {
586+
this.warningUnhooked();
587+
520588
this.validateFields()
521589
.then(values => {
522590
const { onFinish } = this.callbacks;

tests/index.test.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { mount } from 'enzyme';
33
import { resetWarned } from 'rc-util/lib/warning';
4-
import Form, { Field } from '../src';
4+
import Form, { Field, useForm } from '../src';
55
import InfoField, { Input } from './common/InfoField';
66
import { changeValue, getField, matchError } from './common';
77
import timeout from './common/timeout';
@@ -598,4 +598,23 @@ describe('Form.Basic', () => {
598598
);
599599
errorSpy.mockRestore();
600600
});
601+
602+
it('warning if call function before set prop', () => {
603+
resetWarned();
604+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
605+
606+
const Test = () => {
607+
const [form] = useForm();
608+
form.getFieldsValue();
609+
610+
return <Form />;
611+
};
612+
613+
mount(<Test />);
614+
615+
expect(errorSpy).toHaveBeenCalledWith(
616+
'Warning: Instance created by `useForm` is not connect to any Form element. Forget to pass `form` prop?',
617+
);
618+
errorSpy.mockRestore();
619+
});
601620
});

0 commit comments

Comments
 (0)