How to use setState to update state.item in state?
P粉464208937
P粉464208937 2023-08-23 17:35:11
0
2
415
<p>I'm creating an application where users can design their own forms. For example. Specify the name of the field and details of other columns that should be included. </p> <p>This component is available as a JSFiddle. </p> <p>My initial state looks like this: </p> <pre class="brush:php;toolbar:false;">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> ); }</pre> <p>I want to update the state when the user changes any value, but I'm having trouble locating the correct object: </p> <pre class="brush:php;toolbar:false;">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> ); } });</pre> <p>How should I make <code>this.setState</code> so that it updates <code>items[1].name</code>? </p>
P粉464208937
P粉464208937

reply all(2)
P粉798343415

You can achieve this by using the update immutability helper : p>

this.setState({
  items: update(this.state.items, {1: {name: {$set: 'updated field name'}}})
})

Alternatively, if you don't care about being able to detect changes to this using === in the shouldComponentUpdate() lifecycle method, you can edit the state directly and force the component to re- Rendering - This is actually the same as @limelights' answer in that it pulls the object out of state and edits it.

this.state.items[1].name = 'updated field name'
this.forceUpdate()

Later editing added:

Check out the lessons in Simple Component Communication react-training for an example of how to pass a callback function from a parent component that holds state to a child component that needs to trigger a state change.

P粉709307865

Here's how to do it without the helper library:

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 intested 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});
},

If desired, you can combine steps 2 and 3:

let item = {
    ...items[1],
    name: 'newName'
}

Or you can do the whole thing in one line:

this.setState(({items}) => ({
    items: [
        ...items.slice(0,1),
        {
            ...items[1],
            name: 'newName',
        },
        ...items.slice(2)
    ]
}));

Note: I created items as an array. OP used an object. However, the concept is the same.


You can see what's happening in the terminal/console:

❯ node
> items = [{name:'foo'},{name:'bar'},{name:'baz'}]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> clone = [...items]
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ]
> item1 = {...clone[1]}
{ name: 'bar' }
> item1.name = 'bacon'
'bacon'
> clone[1] = item1
{ name: 'bacon' }
> clone
[ { name: 'foo' }, { name: 'bacon' }, { name: 'baz' } ]
> items
[ { name: 'foo' }, { name: 'bar' }, { name: 'baz' } ] // good! we didn't mutate `items`
> items === clone
false // these are different objects
> items[0] === clone[0]
true // we don't need to clone items 0 and 2 because we're not mutating them (efficiency gains!)
> items[1] === clone[1]
false // this guy we copied
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template