Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ should change the heading of the (upcoming) version to include a major version b
-->
# 6.0.0-beta.15

## @rjsf/core

- 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

- Updated `ArrayField` to stop using `nanoid` and instead use `lodash/uniqueId` to fix [#4762](https://github.com/rjsf-team/react-jsonschema-form/issues/4726)
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