How to update nested state properties in React

后端 未结 26 2029
野趣味
野趣味 2020-11-21 06:35

I\'m trying to organize my state by using nested property like this:

this.state = {
   someProperty: {
      flag:true
   }
}

But updating

相关标签:
26条回答
  • 2020-11-21 07:26

    If you are using formik in your project it has some easy way to handle this stuff. Here is the most easiest way to do with formik.

    First set your initial values inside the formik initivalues attribute or in the react. state

    Here, the initial values is define in react state

       state = { 
         data: {
            fy: {
                active: "N"
            }
         }
       }
    

    define above initialValues for formik field inside formik initiValues attribute

    <Formik
     initialValues={this.state.data}
     onSubmit={(values, actions)=> {...your actions goes here}}
    >
    {({ isSubmitting }) => (
      <Form>
        <Field type="checkbox" name="fy.active" onChange={(e) => {
          const value = e.target.checked;
          if(value) setFieldValue('fy.active', 'Y')
          else setFieldValue('fy.active', 'N')
        }}/>
      </Form>
    )}
    </Formik>
    

    Make a console to the check the state updated into string instead of booleanthe formik setFieldValue function to set the state or go with react debugger tool to see the changes iniside formik state values.

    0 讨论(0)
  • 2020-11-21 07:28

    To write it in one line

    this.setState({ someProperty: { ...this.state.someProperty, flag: false} });
    
    0 讨论(0)
  • 2020-11-21 07:28

    Sometimes direct answers are not the best ones :)

    Short version:

    this code

    this.state = {
        someProperty: {
            flag: true
        }
    }
    

    should be simplified as something like

    this.state = {
        somePropertyFlag: true
    }
    

    Long version:

    Currently you shouldn't want to work with nested state in React. Because React is not oriented to work with nested states and all solutions proposed here look as hacks. They don't use the framework but fight with it. They suggest to write not so clear code for doubtful purpose of grouping some properties. So they are very interesting as an answer to the challenge but practically useless.

    Lets imagine the following state:

    {
        parent: {
            child1: 'value 1',
            child2: 'value 2',
            ...
            child100: 'value 100'
        }
    }
    

    What will happen if you change just a value of child1? React will not re-render the view because it uses shallow comparison and it will find that parent property didn't change. BTW mutating the state object directly is considered to be a bad practice in general.

    So you need to re-create the whole parent object. But in this case we will meet another problem. React will think that all children have changed their values and will re-render all of them. Of course it is not good for performance.

    It is still possible to solve that problem by writing some complicated logic in shouldComponentUpdate() but I would prefer to stop here and use simple solution from the short version.

    0 讨论(0)
  • 2020-11-21 07:30

    We use Immer https://github.com/mweststrate/immer to handle these kinds of issues.

    Just replaced this code in one of our components

    this.setState(prevState => ({
       ...prevState,
            preferences: {
                ...prevState.preferences,
                [key]: newValue
            }
    }));
    

    With this

    import produce from 'immer';
    
    this.setState(produce(draft => {
        draft.preferences[key] = newValue;
    }));
    

    With immer you handle your state as a "normal object". The magic happens behind the scene with proxy objects.

    0 讨论(0)
  • 2020-11-21 07:30

    Create a copy of the state:

    let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))
    

    make changes in this object:

    someProperty.flag = "false"
    

    now update the state

    this.setState({someProperty})
    
    0 讨论(0)
  • 2020-11-21 07:30

    I know it is an old question but still wanted to share how i achieved this. Assuming state in constructor looks like this:

      constructor(props) {
        super(props);
    
        this.state = {
          loading: false,
          user: {
            email: ""
          },
          organization: {
            name: ""
          }
        };
    
        this.handleChange = this.handleChange.bind(this);
      }
    

    My handleChange function is like this:

      handleChange(e) {
        const names = e.target.name.split(".");
        const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
        this.setState((state) => {
          state[names[0]][names[1]] = value;
          return {[names[0]]: state[names[0]]};
        });
      }
    

    And make sure you name inputs accordingly:

    <input
       type="text"
       name="user.email"
       onChange={this.handleChange}
       value={this.state.user.firstName}
       placeholder="Email Address"
    />
    
    <input
       type="text"
       name="organization.name"
       onChange={this.handleChange}
       value={this.state.organization.name}
       placeholder="Organization Name"
    />
    
    0 讨论(0)
提交回复
热议问题