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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ should change the heading of the (upcoming) version to include a major version b

- Updated `lodash` import in `fancy-multi-select.tsx` to to be direct import, fixing [#4696](https://github.com/rjsf-team/react-jsonschema-form/issues/4696)

# 6.0.0-beta.13

## @rjsf/core

- Added `experimental_componentUpdateStrategy` prop to `Form` component to control re-render optimization behavior. Supports `'customDeep'` (default, uses deep equality checks that ignore functions), `'shallow'`, and `'always'`

## @rjsf/utils

- Extended `Registry` interface to include optional `experimental_componentUpdateStrategy` property
- Added `shallowEquals()` utility function for shallow equality comparisons

# 6.0.0-beta.12

## @rjsf/core
Expand Down
23 changes: 20 additions & 3 deletions packages/core/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,20 @@ export interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
* `emptyObjectFields`
*/
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
/**
* Controls the component update strategy used by the Form's `shouldComponentUpdate` lifecycle method.
*
* - `'customDeep'`: Uses RJSF's custom deep equality checks via the `deepEquals` utility function,
* which treats all functions as equivalent and provides optimized performance for form data comparisons.
* - `'shallow'`: Uses shallow comparison of props and state (only compares direct properties). This matches React's PureComponent behavior.
* - `'always'`: Always rerenders when called. This matches React's Component behavior.
*
* @default 'customDeep'
*/
experimental_componentUpdateStrategy?: 'customDeep' | 'shallow' | 'always';
/** Optional function that allows for custom merging of `allOf` schemas
*/

experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
// Private
/**
Expand Down Expand Up @@ -514,9 +526,9 @@ export default class Form<
* @returns - True if the component should be updated, false otherwise
*/
shouldComponentUpdate(nextProps: FormProps<T, S, F>, nextState: FormState<T, S, F>): boolean {
return shouldRender(this, nextProps, nextState);
const { experimental_componentUpdateStrategy = 'customDeep' } = this.props;
return shouldRender(this, nextProps, nextState, experimental_componentUpdateStrategy);
}

/** Gets the previously raised customValidate errors.
*
* @returns the previous customValidate errors
Expand Down Expand Up @@ -869,7 +881,11 @@ export default class Form<

/** Returns the registry for the form */
getRegistry(): Registry<T, S, F> {
const { translateString: customTranslateString, uiSchema = {} } = this.props;
const {
translateString: customTranslateString,
uiSchema = {},
experimental_componentUpdateStrategy = 'customDeep',
} = this.props;
const { schema, schemaUtils } = this.state;
const { fields, templates, widgets, formContext, translateString } = getDefaultRegistry<T, S, F>();
return {
Expand All @@ -888,6 +904,7 @@ export default class Form<
schemaUtils,
translateString: customTranslateString || translateString,
globalUiOptions: uiSchema[UI_GLOBAL_OPTIONS_KEY],
experimental_componentUpdateStrategy,
};
}

Expand Down
6 changes: 4 additions & 2 deletions packages/core/src/components/fields/SchemaField.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useCallback, Component, ComponentType } from 'react';
import {
ADDITIONAL_PROPERTY_FLAG,
deepEquals,
descriptionId,
ErrorSchema,
FieldProps,
Expand All @@ -15,6 +14,7 @@ import {
mergeObjects,
Registry,
RJSFSchema,
shouldRender,
StrictRJSFSchema,
TranslatableString,
UI_OPTIONS_KEY,
Expand Down Expand Up @@ -343,7 +343,9 @@ class SchemaField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends Fo
FieldProps<T, S, F>
> {
shouldComponentUpdate(nextProps: Readonly<FieldProps<T, S, F>>) {
return !deepEquals(this.props, nextProps);
const { experimental_componentUpdateStrategy = 'customDeep' } = this.props.registry;

return shouldRender(this, nextProps, this.state, experimental_componentUpdateStrategy);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn't realized that this behavior also applied to SchemaField. Nice catch!


render() {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/test/SchemaField.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('SchemaField', () => {
schemaUtils,
translateString: englishStringTranslator,
globalUiOptions: undefined,
experimental_componentUpdateStrategy: 'customDeep',
});
});
it('should provide expected registry with globalUiOptions as prop', () => {
Expand Down Expand Up @@ -86,6 +87,7 @@ describe('SchemaField', () => {
schemaUtils,
translateString: englishStringTranslator,
globalUiOptions: { copyable: true },
experimental_componentUpdateStrategy: 'customDeep',
});
});
});
Expand Down
Loading