How to Update an Object within a Nested State Using setState in React
In React, it's common to encounter nested state objects that require targeted updates based on user inputs. Consider the following code snippet:
var DynamicForm = React.createClass({ getInitialState: function() { var items = {}; items[1] = { name: 'field 1', populate_at: 'web_start', same_as: 'customer_name', autocomplete_from: 'customer_name', title: '' }; items[2] = { name: 'field 2', populate_at: 'web_end', same_as: 'user_name', autocomplete_from: 'user_name', title: '' }; return { items }; }, render: function() { var _this = this; return ( <div> { Object.keys(this.state.items).map(function (key) { var item = _this.state.items[key]; return ( <div> <PopulateAtCheckboxes this={this} checked={item.populate_at} id={key} populate_at={data.populate_at} /> </div> ); }, this)} <button onClick={this.newFieldEntry}>Create a new field</button> <button onClick={this.saveAndContinue}>Save and Continue</button> </div> ); } });
In this component, the state consists of a nested object, items, which contains items indexed by their position. However, the goal is to update a specific item within the items object upon user interaction.
var PopulateAtCheckboxes = React.createClass({ handleChange: function (e) { item = this.state.items[1]; item.name = 'newName'; items[1] = item; this.setState({items: items}); }, render: function() { var populateAtCheckbox = this.props.populate_at.map(function(value) { return ( <label for={value}> <input type="radio" name={'populate_at'+this.props.id} value={value} onChange={this.handleChange} checked={this.props.checked == value} ref="populate-at"/> {value} </label> ); }, this); return ( <div className="populate-at-checkboxes"> {populateAtCheckbox} </div> ); } });
While the above approach attempts to update the state, it's not the recommended way to mutate nested state objects in React. To ensure immutability and prevent unwanted side effects, the correct approach is to create a shallow copy of the state object, then modify the copy and finally set the state to the modified copy.
handleChange: function (e) { // 1. Make a shallow copy of the items let items = [...this.state.items]; // 2. Make a shallow copy of the item you want to mutate let item = {...items[1]}; // 3. Replace the property you're interested in item.name = 'newName'; // 4. Put it back into our array. N.B. we *are* mutating the array here, // but that's why we made a copy first items[1] = item; // 5. Set the state to our new copy this.setState({items}); },
Alternatively, if you prefer a more concise approach, you can use the spread syntax to achieve the same result in one line:
this.setState(({items}) => ({ items: [ ...items.slice(0,1), { ...items[1], name: 'newName', }, ...items.slice(2) ] }));
The above is the detailed content of How to Update a Nested Object within State in React Using setState?. For more information, please follow other related articles on the PHP Chinese website!