Skip to content

Reimplement #1755 and and #2460 in new Form.tsx #3052

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 27, 2022
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ should change the heading of the (upcoming) version to include a major version b
- Added `ui:duplicateKeySuffixSeparator` to customize how duplicate object keys are renamed when using `additionalProperties`.
- The `extraErrors` are now consistently appended onto the end of the schema validation-based `errors` information that is returned via the `onErrors()` callback when submit fails.
- In addition, the extra information provided by AJV is no longer stripped from the `errors` during the merge process, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596).
- Correctly call the `onChange` handler in the new set of props if it changed, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1708).
- Fixed race condition for `onChange` when `formData` is controlled prop, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/513),

## @rjsf/antd
- Fix esm build to use `@rollup/plugin-replace` to replace `antd/lib` and `rc-picker/lib` with `antd/es` and `rc-picker/es` respectively, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2962)
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ export default class Form<T = any, F = any> extends Component<
if (
!deepEquals(nextState.formData, nextProps.formData) &&
!deepEquals(nextState.formData, this.state.formData) &&
this.props.onChange
nextProps.onChange
) {
this.props.onChange(nextState);
nextProps.onChange(nextState);
}
this.setState(nextState);
}
Expand Down Expand Up @@ -562,7 +562,7 @@ export default class Form<T = any, F = any> extends Component<
}
this.setState(
state as FormState<T, F>,
() => onChange && onChange(this.state)
() => onChange && onChange({ ...this.state, ...state })
);
};

Expand Down
106 changes: 105 additions & 1 deletion packages/core/test/Form_test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from "chai";
import sinon from "sinon";
import React, { createRef } from "react";
import { renderIntoDocument, Simulate } from "react-dom/test-utils";
import { renderIntoDocument, act, Simulate } from "react-dom/test-utils";
import { render, findDOMNode } from "react-dom";
import { Portal } from "react-portal";
import validator, { customizeValidator } from "@rjsf/validator-ajv6";
Expand Down Expand Up @@ -1012,6 +1012,52 @@ describeRepeated("Form common", (createFormComponent) => {
uiSchema,
});
});
it("should call last provided change handler", async () => {
const schema = {
type: "object",
properties: {
foo: {
type: "string",
default: "bar",
},
},
};

const secondOnChange = sandbox.spy();

const { comp, onChange } = createFormComponent({
schema,
formData: { foo: "bar1" },
});

act(() => {
setProps(comp, {
schema,
formData: {},
onChange,
});
});

sinon.assert.callCount(onChange, 1);

act(() => {
setProps(comp, {
schema,
formData: { foo: "bar2" },
});
});

act(() => {
setProps(comp, {
schema,
formData: {},
onChange: secondOnChange,
});
});

sinon.assert.callCount(onChange, 1);
sinon.assert.callCount(secondOnChange, 1);
});
});
describe("Blur handler", () => {
it("should call provided blur handler on form input blur event", () => {
Expand Down Expand Up @@ -3402,4 +3448,62 @@ describe("Form omitExtraData and liveOmit", () => {

expect(node.querySelectorAll(".error-detail li")).to.have.length.of(2);
});
describe("Calling onChange right after updating a Form with props formData", () => {
const schema = {
type: "array",
items: {
type: "string",
},
};

let changed = false;
class ArrayThatTriggersOnChangeRightAfterUpdated extends React.Component {
componentDidUpdate = () => {
if (changed) {
return;
}
changed = true;
this.props.onChange([...this.props.formData, "test"]);
};
render() {
const { ArrayField } = this.props.registry.fields;
return <ArrayField {...this.props} />;
}
}

const uiSchema = {
"ui:field": ArrayThatTriggersOnChangeRightAfterUpdated,
};

const props = {
schema,
uiSchema,
};

class Container extends React.Component {
constructor(props) {
super(props);
this.state = {};
}

onChange = ({ formData }) => {
this.setState({ formData });
};

render() {
return (
<Form {...this.props} {...this.state} onChange={this.onChange} />
);
}
}

it("doesn't cause a race condition", () => {
const { node } = createComponent(Container, { ...props });

Simulate.click(node.querySelector(".array-item-add button"));

expect(node.querySelector("#root_0")).to.exist;
expect(node.querySelector("#root_1").getAttribute("value")).to.eq("test");
});
});
});