React-jsonschema-form: Not able to control the`formData` in redux state

Created on 24 Nov 2018  路  5Comments  路  Source: rjsf-team/react-jsonschema-form

Description

We get a formData object from the server that we allow the user to edit and we are using lodash ._set-object to update parts of that formData depending on what part of the formData the user updates.

Steps to Reproduce

We are trying to control the state of formData in redux state. We try to use componentWillReceiveProps, but can't get the updated state back as a props. We put our action in onChange function and it changes the state correctly when we type in text. But when we finish typing it return back to empty string value as it can't get updated state to the component as a props, and then the onChange function triggers the action once again because value of the input is empty.

We are trying to get the current value locally by setting the state inside the component but getting this error;

Uncaught Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops

This is our function;

onChange = ({ formData }) => {
const { path, editKeyword } = this.props;
const inputValue =formDataData[editKeyword];

let prevformData = this.props.formData;

// update the object using
const updatedFormData = _.set(prevFormData, path, inputValue);

// action
this.props.setCurrentFormData(updatedformData);};

We also tried the following with no luck;

onChange = ({ formData }) => {
const { path, editKeyword } = this.props;
const inputValue = formData[editKeyword];
console.log("input value ", inputValue);

let prevFormData = this.props.formData;

const updatedFormData = _.set(prevformData, path, inputValue);

// when we try to update local state
this.setState({ FormData: updatedformData})

};

Anyone encountered anything similar? We can't directly use the formData from the form-input because we are merging values from server and the user input.

Most helpful comment

The issue is here https://github.com/mozilla-services/react-jsonschema-form/blob/master/src/utils.js#L190 - When a Form is updated, it checks computed formData against the formData prop, if there is a difference, then the onChange handler is called. If the formData value is falsey, then the this will result in an infinite loop, as the computed formData and props.formData will never be the same.

Update: I've opened a PR to fix this issue

All 5 comments

@mikaelmh The React error that you have pasted is usually caused by calling an event handler/callback instead of assigning it, for example:

class Clicker extends React.Component {
  constructor() {
    super()
    this.state = {
      on: true
    }
    this.handler = this.handler.bind(this)
  }

  handler() {
    this.setState({ on: !this.state.on })
  }

  render() {
    return <button onClick={this.handler()}>Click me</button>
  }
}

You can see a live version of this here https://codesandbox.io/s/2pr78pv3pp

The solution to this problem is to change the handler to an assignment:

  render() {
    return <button onClick={this.handler}>Click me</button>
  }

Can you post the render method where you are rendering the form, or post a minimal reproduction in https://codesandbox.io or somewhere similar?

@LucianBuzzo apologize for our late reply. We have been able to make a sandbox that you can have a look at ;

https://codesandbox.io/s/oo3qknl296

Our requirement is that we will receive initial state of formData from the server, and we need to update a specific part of it using the path only (e.g. task[0].title or task.title like it would be in the example). We achieved that functionality and put it in onChange function as you can see in the sandbox. However, If you uncomment where we are trying to set the updated state, you see the error Maximum update depth exceded...

Thoughts on how we can do this correctly? Thank you.

@mikaelmh I looked at the sandbox you made and I think the issue comes down to the way that you are controlling the <Form /> component. It seems that setting formData to an empty string at the bottom of onChange() causes this error. If you change the method to this it should work as expected:

onChange = ({ formData }) => {
    const { path, editKeyword } = this.props;
    const inputValue = formData[editKeyword];
    // console.log("input value ", inputValue);

    let prevFormData = this.props.formData;

    const updatedFormData = _.set(prevFormData, path, inputValue);

    this.props.updateForm(formData);
    this.setState({ formData });
};

For a completely minimal reproduction of this issue take a look at this:
https://codesandbox.io/s/yk6w0z9qxz
It appears that setting formData to any falsey value will cause the error Maximum update depth exceeded....
Setting it to a truthey value (non-empty string, true, empty object etc) will not cause the same behaviour.

The issue is here https://github.com/mozilla-services/react-jsonschema-form/blob/master/src/utils.js#L190 - When a Form is updated, it checks computed formData against the formData prop, if there is a difference, then the onChange handler is called. If the formData value is falsey, then the this will result in an infinite loop, as the computed formData and props.formData will never be the same.

Update: I've opened a PR to fix this issue

@LucianBuzzo thank you, this was great! We were able to make it work this past weekend. Awesome feedback.

Was this page helpful?
0 / 5 - 0 ratings