Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 452
nicholas Avatar asked Jul 29 '14 04:07

nicholas


1 Answers

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

like image 137
go-oleg Avatar answered Oct 01 '22 17:10

go-oleg