diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c22a6c7e..fbb97fa911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,13 +17,19 @@ should change the heading of the (upcoming) version to include a major version b --> # 5.13.3 -## @rjsf/utils +## @rjsf/antd -- Updated `toPathSchemaInternal()` util to generate correct path schemas for fixed arrays by picking up individual schemas in the `items` array, fixing [#3909](https://github.com/rjsf-team/react-jsonschema-form/issues/3909) +- Fixed the `SelectWidget` so that filtering works by reworking how `options` are passed to the underlying `Select` ## @rjsf/core - Replaced the deprecated `UNSAFE_componentWillReceiveProps()` method in the Form.tsx component with an improved solution utilizing the React lifecycle methods: `getSnapshotBeforeUpdate()` and `componentDidUpdate()`. Fixing [#1794](https://github.com/rjsf-team/react-jsonschema-form/issues/1794) +- Fixed the `ArrayField` implementation to never pass an undefined schema for fixed arrays to other methods, fixing [#3924](https://github.com/rjsf-team/react-jsonschema-form/issues/3924) +- Fixed a refresh issue in `getSnapshotBeforeUpdate()` and `componentDidUpdate()` caused by the fix for #1794, fixing [#3927](https://github.com/rjsf-team/react-jsonschema-form/issues/3927) + +## @rjsf/utils + +- Updated `toPathSchemaInternal()` util to generate correct path schemas for fixed arrays by picking up individual schemas in the `items` array, fixing [#3909](https://github.com/rjsf-team/react-jsonschema-form/issues/3909) # 5.13.2 diff --git a/packages/core/src/components/Form.tsx b/packages/core/src/components/Form.tsx index 9044ab56fe..aa43ffea14 100644 --- a/packages/core/src/components/Form.tsx +++ b/packages/core/src/components/Form.tsx @@ -281,35 +281,45 @@ export default class Form< } /** - * `getSnapshotBeforeUpdate` is a React lifecycle method that is invoked right before the most recently rendered output is committed to the DOM. - * It enables your component to capture current values (e.g., scroll position) before they are potentially changed. + * `getSnapshotBeforeUpdate` is a React lifecycle method that is invoked right before the most recently rendered + * output is committed to the DOM. It enables your component to capture current values (e.g., scroll position) before + * they are potentially changed. * - * In this case, it checks if the `formData` prop has changed since the last render. If it has, it computes the next state of the component - * using `getStateFromProps` method and returns it along with a `shouldUpdate` flag set to `true`. This ensures that we have the most up-to-date + * In this case, it checks if the props have changed since the last render. If they have, it computes the next state + * of the component using `getStateFromProps` method and returns it along with a `shouldUpdate` flag set to `true` IF + * the `nextState` and `prevState` are different, otherwise `false`. This ensures that we have the most up-to-date * state ready to be applied in `componentDidUpdate`. * - * If `formData` hasn't changed, it simply returns an object with `shouldUpdate` set to `false`, indicating that a state update is not necessary. + * If `formData` hasn't changed, it simply returns an object with `shouldUpdate` set to `false`, indicating that a + * state update is not necessary. * * @param prevProps - The previous set of props before the update. - * @returns Either an object containing the next state and a flag indicating that an update should occur, or an object with a flag indicating that an update is not necessary. + * @param prevState - The previous state before the update. + * @returns Either an object containing the next state and a flag indicating that an update should occur, or an object + * with a flag indicating that an update is not necessary. */ getSnapshotBeforeUpdate( - prevProps: FormProps + prevProps: FormProps, + prevState: FormState ): { nextState: FormState; shouldUpdate: true } | { shouldUpdate: false } { - if (!deepEquals(this.props.formData, prevProps.formData)) { + if (!deepEquals(this.props, prevProps)) { const nextState = this.getStateFromProps(this.props, this.props.formData); - return { nextState, shouldUpdate: true }; + const shouldUpdate = !deepEquals(nextState, prevState); + return { nextState, shouldUpdate }; } return { shouldUpdate: false }; } /** - * `componentDidUpdate` is a React lifecycle method that is invoked immediately after updating occurs. This method is not called for the initial render. + * `componentDidUpdate` is a React lifecycle method that is invoked immediately after updating occurs. This method is + * not called for the initial render. * - * Here, it checks if an update is necessary based on the `shouldUpdate` flag received from `getSnapshotBeforeUpdate`. If an update is required, - * it applies the next state and, if needed, triggers the `onChange` handler to inform about changes. + * Here, it checks if an update is necessary based on the `shouldUpdate` flag received from `getSnapshotBeforeUpdate`. + * If an update is required, it applies the next state and, if needed, triggers the `onChange` handler to inform about + * changes. * - * This method effectively replaces the deprecated `UNSAFE_componentWillReceiveProps`, providing a safer alternative to handle prop changes and state updates. + * This method effectively replaces the deprecated `UNSAFE_componentWillReceiveProps`, providing a safer alternative + * to handle prop changes and state updates. * * @param _ - The previous set of props. * @param prevState - The previous state of the component before the update. diff --git a/packages/core/src/components/fields/ArrayField.tsx b/packages/core/src/components/fields/ArrayField.tsx index fec304c9f2..f236b8ea3a 100644 --- a/packages/core/src/components/fields/ArrayField.tsx +++ b/packages/core/src/components/fields/ArrayField.tsx @@ -743,9 +743,9 @@ class ArrayField= itemSchemas.length; const itemSchema = - additional && isObject(schema.additionalItems) + (additional && isObject(schema.additionalItems) ? schemaUtils.retrieveSchema(schema.additionalItems as S, itemCast) - : itemSchemas[index]; + : itemSchemas[index]) || {}; const itemIdPrefix = idSchema.$id + idSeparator + index; const itemIdSchema = schemaUtils.toIdSchema(itemSchema, itemIdPrefix, itemCast, idPrefix, idSeparator); const itemUiSchema = additional diff --git a/packages/core/test/ArrayField.test.jsx b/packages/core/test/ArrayField.test.jsx index 4024574c7e..78d3dd6e66 100644 --- a/packages/core/test/ArrayField.test.jsx +++ b/packages/core/test/ArrayField.test.jsx @@ -1985,6 +1985,29 @@ describe('ArrayField', () => { expect(node.querySelectorAll('textarea').length).to.eql(2); }); + it('[fixed] should silently handle additional formData not covered by fixed array', () => { + const { node, onSubmit } = createFormComponent({ + schema: { + type: 'array', + items: [ + { + type: 'string', + }, + { + type: 'string', + }, + ], + }, + formData: ['foo', 'bar', 'baz'], + }); + expect(node.querySelectorAll('input').length).to.eql(2); + submitForm(node); + + sinon.assert.calledWithMatch(onSubmit.lastCall, { + formData: ['foo', 'bar', 'baz'], + }); + }); + describe('operations for additional items', () => { const { node, onChange } = createFormComponent({ schema: schemaAdditional,