Skip to content

Commit eb7e928

Browse files
Feature: Performance optimization, live validate/omit onBlur (#4812)
1 parent f80f462 commit eb7e928

File tree

9 files changed

+1735
-1388
lines changed

9 files changed

+1735
-1388
lines changed

CHANGELOG.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ it according to semantic versioning. For example, if your PR adds a breaking cha
1515
should change the heading of the (upcoming) version to include a major version bump.
1616
1717
-->
18+
# 6.0.0-beta.23
19+
20+
## @rjsf/core
21+
22+
- Updated `FormProps` to add new `onChange`/`onBlur` values for the `liveValidate` and `liveOmit` props, deprecating the `boolean` aspect of them
23+
- Updated `Form` to support the new feature to do `onBlur` handling of `liveValidate` and `liveOmit`
24+
25+
## Dev / docs / playground
26+
- Updated the playground to switch `liveValidate` and `liveOmit` from checkboxes to radio buttons for the new options
27+
- Updated `form-props.md` and `v6x upgrade guide.md` to document the new feature and deprecation
28+
1829
# 6.0.0-beta.22
1930

2031
## @rjsf/antd
@@ -44,7 +55,7 @@ should change the heading of the (upcoming) version to include a major version b
4455
- BREAKING CHANGE: Updated `ArrayFieldTemplate` to remove the `ArrayFieldItemTemplate` render in favor of simply using `items` due to `ArrayField` changes
4556
- BREAKING CHANGE: Updated `ArrayFieldItemButtonsTemplate` to replace the old callback-generator functions with the new memoizable callback functions
4657
- Fixed a bug in `Form` to avoid getting errors being reported at the root level via `onChange` when there aren't
47-
- Refactored LayoutGridField as function components instead of a single class component.
58+
- Refactored `LayoutGridField` as function components instead of a single class component.
4859

4960
## @rjsf/daisyui
5061

@@ -127,8 +138,7 @@ should change the heading of the (upcoming) version to include a major version b
127138
- Updated the `utility-functions.md` documentation to add the new `useDeepCompareMemo()` hook
128139
- Updated the `v6.x upgrade guide.md` documentation to add the BREAKING CHANGES to the `ArrayFieldTemplateProps`, `ArrayFieldItemTemplateType`, `ArrayFieldItemButtonsTemplateType`, `FieldTemplateProps`, `ObjectFieldTemplateProps` and `WrapIfAdditionalTemplateProps` interface props changes and the `useDeepCompareMemo()` hook
129140
- Added documentation for the `nameGenerator` prop in `form-props.md` and v6.x upgrade guide
130-
- Updated '@rjsf/snapshot-tests' package to explicitly depend on '@rjsf/core' to build first, fixing an error with parallelized builds
131-
141+
- Updated `@rjsf/snapshot-tests` package to explicitly depend on `@rjsf/core` to build first, fixing an error with parallelized builds
132142

133143
# 6.0.0-beta.21
134144

packages/core/src/components/Form.tsx

Lines changed: 61 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,28 @@ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
168168
* @deprecated - In a future release, this switch may be replaced by making `validator` prop optional
169169
*/
170170
noValidate?: boolean;
171-
/** If set to true, the form will perform validation and show any validation errors whenever the form data is changed,
172-
* rather than just on submit
171+
/** Flag that describes when live validation will be performed. Live validation means that the form will perform
172+
* validation and show any validation errors whenever the form data is updated, rather than just on submit.
173+
*
174+
* If no value (or `false`) is provided, then live validation will not happen. If `true` or `onChange` is provided for
175+
* the flag, then live validation will be performed after processing of all pending changes has completed. If `onBlur`
176+
* is provided, then live validation will be performed when a field that was updated is blurred (as a performance
177+
* optimization).
178+
*
179+
* @deprecated - In a future major release, the `boolean` options for this flag will be removed
173180
*/
174-
liveValidate?: boolean;
175-
/** If `omitExtraData` and `liveOmit` are both set to true, then extra form data values that are not in any form field
176-
* will be removed whenever `onChange` is called. Set to `false` by default
181+
liveValidate?: boolean | 'onChange' | 'onBlur';
182+
/** Flag that describes when live omit will be performed. Live omit happens only when `omitExtraData` is also set to
183+
* to `true` and the form's data is updated by the user.
184+
*
185+
* If no value (or `false`) is provided, then live omit will not happen. If `true` or `onChange` is provided for
186+
* the flag, then live omit will be performed after processing of all pending changes has completed. If `onBlur`
187+
* is provided, then live omit will be performed when a field that was updated is blurred (as a performance
188+
* optimization).
189+
*
190+
* @deprecated - In a future major release, the `boolean` options for this flag will be removed
177191
*/
178-
liveOmit?: boolean;
192+
liveOmit?: boolean | 'onChange' | 'onBlur';
179193
/** If set to true, then extra form data values that are not in any form field will be removed whenever `onSubmit` is
180194
* called. Set to `false` by default.
181195
*/
@@ -834,11 +848,11 @@ export default class Form<
834848
retrievedSchema = newState.retrievedSchema;
835849
}
836850

837-
const mustValidate = !noValidate && liveValidate;
851+
const mustValidate = !noValidate && (liveValidate === true || liveValidate === 'onChange');
838852
let state: Partial<FormState<T, S, F>> = { formData, schema };
839853
let newFormData = formData;
840854

841-
if (omitExtraData === true && liveOmit === true) {
855+
if (omitExtraData === true && (liveOmit === true || liveOmit === 'onChange')) {
842856
newFormData = this.omitExtraData(formData);
843857
state = {
844858
formData: newFormData,
@@ -944,16 +958,53 @@ export default class Form<
944958
};
945959

946960
/** Callback function to handle when a field on the form is blurred. Calls the `onBlur` callback for the `Form` if it
947-
* was provided.
961+
* was provided. Also runs any live validation and/or live omit operations if the flags indicate they should happen
962+
* during `onBlur`.
948963
*
949964
* @param id - The unique `id` of the field that was blurred
950965
* @param data - The data associated with the field that was blurred
951966
*/
952967
onBlur = (id: string, data: any) => {
953-
const { onBlur } = this.props;
968+
const { onBlur, omitExtraData, liveOmit, liveValidate } = this.props;
954969
if (onBlur) {
955970
onBlur(id, data);
956971
}
972+
if ((omitExtraData === true && liveOmit === 'onBlur') || liveValidate === 'onBlur') {
973+
const { onChange, extraErrors } = this.props;
974+
const { formData } = this.state;
975+
let newFormData: T | undefined = formData;
976+
let state: Partial<FormState<T, S, F>> = { formData: newFormData };
977+
if (omitExtraData === true && liveOmit === 'onBlur') {
978+
newFormData = this.omitExtraData(formData);
979+
state = { formData: newFormData };
980+
}
981+
if (liveValidate === 'onBlur') {
982+
const { schema, schemaUtils, errorSchema, customErrors, retrievedSchema } = this.state;
983+
const liveValidation = this.liveValidate(
984+
schema,
985+
schemaUtils,
986+
errorSchema,
987+
newFormData,
988+
extraErrors,
989+
customErrors,
990+
retrievedSchema,
991+
);
992+
state = { formData: newFormData, ...liveValidation, customErrors };
993+
}
994+
const hasChanges = Object.keys(state)
995+
// Filter out `schemaValidationErrors` and `schemaValidationErrorSchema` since they aren't IChangeEvent props
996+
.filter((key) => !key.startsWith('schemaValidation'))
997+
.some((key) => {
998+
const oldData = _get(this.state, key);
999+
const newData = _get(state, key);
1000+
return !deepEquals(oldData, newData);
1001+
});
1002+
this.setState(state as FormState<T, S, F>, () => {
1003+
if (onChange && hasChanges) {
1004+
onChange(toIChangeEvent({ ...this.state, ...state }), id);
1005+
}
1006+
});
1007+
}
9571008
};
9581009

9591010
/** Callback function to handle when a field on the form is focused. Calls the `onFocus` callback for the `Form` if it

0 commit comments

Comments
 (0)