Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ should change the heading of the (upcoming) version to include a major version b
## @rjsf/core

- Updated `ArrayField` `onSelectChange` to not pass `name` in the `path` since the `ObjectField` will automatically add it [#4733](https://github.com/rjsf-team/react-jsonschema-form/issues/4733)
- Updated `Form` to optimize the need for live validation in an attempt to improve performance, potentially fixing [#3616](https://github.com/rjsf-team/react-jsonschema-form/issues/3616)

## @rjsf/semantic-ui

Expand Down
17 changes: 14 additions & 3 deletions packages/core/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,18 @@ export default class Form<
prevState: FormState<T, S, F>,
): { nextState: FormState<T, S, F>; shouldUpdate: true } | { shouldUpdate: false } {
if (!deepEquals(this.props, prevProps)) {
// Compare the previous props formData against the current props formData
const formDataChangedFields = getChangedFields(this.props.formData, prevProps.formData);
// Compare the current props formData against the current state's formData to determine if the new props were the
// result of the onChange from the existing state formData
const stateDataChangedFields = getChangedFields(this.props.formData, this.state.formData);
const isSchemaChanged = !deepEquals(prevProps.schema, this.props.schema);
// When formData is not an object, getChangedFields returns an empty array.
// In this case, deepEquals is most needed to check again.
const isFormDataChanged =
formDataChangedFields.length > 0 || !deepEquals(prevProps.formData, this.props.formData);
const isStateDataChanged =
stateDataChangedFields.length > 0 || !deepEquals(this.state.formData, this.props.formData);
const nextState = this.getStateFromProps(
this.props,
this.props.formData,
Expand All @@ -360,6 +366,8 @@ export default class Form<
isSchemaChanged || isFormDataChanged ? undefined : this.state.retrievedSchema,
isSchemaChanged,
formDataChangedFields,
// Skip live validation for this request if no form data has changed from the last state
!isStateDataChanged,
);
const shouldUpdate = !deepEquals(nextState, prevState);
return { nextState, shouldUpdate };
Expand Down Expand Up @@ -415,14 +423,15 @@ export default class Form<
retrievedSchema?: S,
isSchemaChanged = false,
formDataChangedFields: string[] = [],
skipLiveValidate = false,
): FormState<T, S, F> {
const state: FormState<T, S, F> = this.state || {};
const schema = 'schema' in props ? props.schema : this.props.schema;
const validator = 'validator' in props ? props.validator : this.props.validator;
const uiSchema: UiSchema<T, S, F> = ('uiSchema' in props ? props.uiSchema! : this.props.uiSchema!) || {};
const edit = typeof inputFormData !== 'undefined';
const liveValidate = 'liveValidate' in props ? props.liveValidate : this.props.liveValidate;
const mustValidate = edit && !props.noValidate && liveValidate;
const mustValidate = edit && !props.noValidate && liveValidate && !skipLiveValidate;
const experimental_defaultFormStateBehavior =
'experimental_defaultFormStateBehavior' in props
? props.experimental_defaultFormStateBehavior
Expand Down Expand Up @@ -770,7 +779,8 @@ export default class Form<
// If the newValue is not on the root path, then set it into the form data
_set(formData, path, newValue);
}
const newState = this.getStateFromProps(this.props, formData);
// Pass true to skip live validation in `getStateFromProps()` since we will do it a bit later
const newState = this.getStateFromProps(this.props, formData, undefined, undefined, undefined, true);
formData = newState.formData;
retrievedSchema = newState.retrievedSchema;
}
Expand All @@ -793,7 +803,8 @@ export default class Form<
_set(errorSchemaCopy, path, newErrorSchema);
newErrorSchema = errorSchemaCopy;
}
if (mustValidate) {
// If there are pending changes in the queue, skip live validation since it will happen with the last change
if (mustValidate && this.pendingChanges.length === 1) {
const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
let errors = schemaValidation.errors;
let errorSchema = schemaValidation.errorSchema;
Expand Down