Skip to content

Commit d7b59a3

Browse files
chore: add retrieveSchema at Form state to memoize the result of schemUtils.retrieveSchema (#3970)
* doesn't retrieveSchema at onChange * Update retrieveSchema if changed during onChange * Update CHANGELOG
1 parent 1cf8445 commit d7b59a3

File tree

3 files changed

+29
-10
lines changed

3 files changed

+29
-10
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ should change the heading of the (upcoming) version to include a major version b
1717
-->
1818
# 5.14.3
1919

20+
## @rjsf/core
21+
22+
- add `retrieveSchema` at `Form` state to memoize the result of `schemUtils.retrieveSchema`
23+
2024
## @rjsf/fluentui-rc
2125
- Updated README.md references
2226
- Fixed width of `ArrayFieldItemTemplate` items

packages/core/src/components/Form.tsx

+23-10
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ export interface FormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
238238
* `extraErrors`
239239
*/
240240
schemaValidationErrorSchema: ErrorSchema<T>;
241+
// Private
242+
/** @description result of schemaUtils.retrieveSchema(schema, formData). This a memoized value to avoid re calculate at internal functions (getStateFromProps, onChange) */
243+
retrievedSchema: S;
241244
}
242245

243246
/** The event data passed when changes have been made to the form, includes everything from the `FormState` except
@@ -303,7 +306,11 @@ export default class Form<
303306
prevState: FormState<T, S, F>
304307
): { nextState: FormState<T, S, F>; shouldUpdate: true } | { shouldUpdate: false } {
305308
if (!deepEquals(this.props, prevProps)) {
306-
const nextState = this.getStateFromProps(this.props, this.props.formData);
309+
const nextState = this.getStateFromProps(
310+
this.props,
311+
this.props.formData,
312+
prevProps.schema !== this.props.schema ? undefined : this.state.retrievedSchema
313+
);
307314
const shouldUpdate = !deepEquals(nextState, prevState);
308315
return { nextState, shouldUpdate };
309316
}
@@ -352,7 +359,7 @@ export default class Form<
352359
* @param inputFormData - The new or current data for the `Form`
353360
* @returns - The new state for the `Form`
354361
*/
355-
getStateFromProps(props: FormProps<T, S, F>, inputFormData?: T): FormState<T, S, F> {
362+
getStateFromProps(props: FormProps<T, S, F>, inputFormData?: T, retrievedSchema?: S): FormState<T, S, F> {
356363
const state: FormState<T, S, F> = this.state || {};
357364
const schema = 'schema' in props ? props.schema : this.props.schema;
358365
const uiSchema: UiSchema<T, S, F> = ('uiSchema' in props ? props.uiSchema! : this.props.uiSchema!) || {};
@@ -372,7 +379,7 @@ export default class Form<
372379
schemaUtils = createSchemaUtils<T, S, F>(props.validator, rootSchema, experimental_defaultFormStateBehavior);
373380
}
374381
const formData: T = schemaUtils.getDefaultFormState(schema, inputFormData) as T;
375-
const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
382+
const _retrievedSchema = retrievedSchema ?? schemaUtils.retrieveSchema(schema, formData);
376383

377384
const getCurrentErrors = (): ValidationData<T> => {
378385
if (props.noValidate) {
@@ -394,7 +401,7 @@ export default class Form<
394401
let schemaValidationErrors: RJSFValidationError[] = state.schemaValidationErrors;
395402
let schemaValidationErrorSchema: ErrorSchema<T> = state.schemaValidationErrorSchema;
396403
if (mustValidate) {
397-
const schemaValidation = this.validate(formData, schema, schemaUtils, retrievedSchema);
404+
const schemaValidation = this.validate(formData, schema, schemaUtils, _retrievedSchema);
398405
errors = schemaValidation.errors;
399406
errorSchema = schemaValidation.errorSchema;
400407
schemaValidationErrors = errors;
@@ -410,7 +417,7 @@ export default class Form<
410417
errors = merged.errors;
411418
}
412419
const idSchema = schemaUtils.toIdSchema(
413-
retrievedSchema,
420+
_retrievedSchema,
414421
uiSchema['ui:rootFieldId'],
415422
formData,
416423
props.idPrefix,
@@ -427,6 +434,7 @@ export default class Form<
427434
errorSchema,
428435
schemaValidationErrors,
429436
schemaValidationErrorSchema,
437+
retrievedSchema: _retrievedSchema,
430438
};
431439
return nextState;
432440
}
@@ -550,19 +558,21 @@ export default class Form<
550558
*/
551559
onChange = (formData: T | undefined, newErrorSchema?: ErrorSchema<T>, id?: string) => {
552560
const { extraErrors, omitExtraData, liveOmit, noValidate, liveValidate, onChange } = this.props;
553-
const { schemaUtils, schema } = this.state;
561+
const { schemaUtils, schema, retrievedSchema } = this.state;
562+
554563
if (isObject(formData) || Array.isArray(formData)) {
555-
const newState = this.getStateFromProps(this.props, formData);
564+
const newState = this.getStateFromProps(this.props, formData, retrievedSchema);
556565
formData = newState.formData;
557566
}
558567

559568
const mustValidate = !noValidate && liveValidate;
560569
let state: Partial<FormState<T, S, F>> = { formData, schema };
561570
let newFormData = formData;
562571

572+
let _retrievedSchema: S | undefined;
563573
if (omitExtraData === true && liveOmit === true) {
564-
const retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
565-
const pathSchema = schemaUtils.toPathSchema(retrievedSchema, '', formData);
574+
_retrievedSchema = schemaUtils.retrieveSchema(schema, formData);
575+
const pathSchema = schemaUtils.toPathSchema(_retrievedSchema, '', formData);
566576

567577
const fieldNames = this.getFieldNames(pathSchema, formData);
568578

@@ -573,7 +583,7 @@ export default class Form<
573583
}
574584

575585
if (mustValidate) {
576-
const schemaValidation = this.validate(newFormData);
586+
const schemaValidation = this.validate(newFormData, schema, schemaUtils, retrievedSchema);
577587
let errors = schemaValidation.errors;
578588
let errorSchema = schemaValidation.errorSchema;
579589
const schemaValidationErrors = errors;
@@ -600,6 +610,9 @@ export default class Form<
600610
errors: toErrorList(errorSchema),
601611
};
602612
}
613+
if (_retrievedSchema) {
614+
state.retrievedSchema = _retrievedSchema;
615+
}
603616
this.setState(state as FormState<T, S, F>, () => onChange && onChange({ ...this.state, ...state }, id));
604617
};
605618

packages/core/test/Form.test.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ describeRepeated('Form common', (createFormComponent) => {
140140
schemaValidationErrors: undefined,
141141
schemaValidationErrorSchema: undefined,
142142
schemaUtils: sinon.match.object,
143+
retrievedSchema: schema,
143144
});
144145
});
145146
});
@@ -1480,6 +1481,7 @@ describeRepeated('Form common', (createFormComponent) => {
14801481
schemaValidationErrors: undefined,
14811482
schemaValidationErrorSchema: undefined,
14821483
schemaUtils: sinon.match.object,
1484+
retrievedSchema: formProps.schema,
14831485
});
14841486
});
14851487
});

0 commit comments

Comments
 (0)