nicholas
nicholas

Reputation: 14563

Updating deep ReactJS state

I have an array of items in a ReactJS component state that I'm iterating over to create a form. My question is: How do I best update those items when the fields change?

For example:

var items = this.state.foo.bar.items.map(function(item, i) {
    return <input value={item.baz} onChange={??}
});

What would my onChange handler look like in this case? Do I change the item.baz property directly, then this.setState(state)? Seems wrong. I'm looking at the React immutability helpers, but see how to work with array indexes.

Thanks.

Upvotes: 10

Views: 8340

Answers (2)

Blaine Hatab
Blaine Hatab

Reputation: 1676

Thought I'd just throw this library out there because it was specifically designed for deeply nested react state,

https://github.com/mquan/cortex

You can update items within each component and it automatically trickles up without you having to define callbacks to pass the event up.

Upvotes: 2

go-oleg
go-oleg

Reputation: 19480

You could use the index to update the correct array item by passing it to onChange via bind and then dynamically building the object to pass to update:

var Hello = React.createClass({
    getInitialState : function() {
      return  {
        foo : {
          bar : {
            items : [ { baz : 1 }, { baz : 2 }, { baz : 3 } ]
          }
        }
      };
    },
    onChange : function( idx, item, event ) {
      var objForUpdate = { foo: { bar: { items : {} } } };
      objForUpdate.foo.bar.items[ idx ] = { $set : { baz : event.target.value } };
      var newData = React.addons.update( this.state, objForUpdate );
      this.setState( newData );
    },
    render: function() {
      var _this = this;
      var items = this.state.foo.bar.items.map(function(item, i) {
        return <input value={item.baz} onChange={_this.onChange.bind( _this, i, item )}></input>
      });
      return <div>{items}</div>;
    }
});

My understanding that this only has an advantage over something like

onChange : function( idx, item, event ) {
  item.baz = event.target.value;
  this.setState( this.state );
}

if you are going to override shouldComponentUpdate and be more selective about when to rerender than every time this.setState() is called.

jsfiddle

Upvotes: 6

Related Questions