What’s the best way to mutate complex state in React.js?

What’s the best way to mutate complex state in React.js?

Here’s a simple React component that renders a list, when a list item get clicked, the item adds a className called selected.

var CX = React.addons.classSet;
var List = React.createClass({
  getInitialState: function(){
    return {
      items: this.props.items
    }
  },

  handleItemClick: function(item){
    item.isSelected = true;
    //hack
    this.forceUpdate();
  },

  render: function(){
    var self = this;
    var items = this.state.items.map(function(item, index){
      var className = CX({
        'item': true,
        'selected': item.isSelected
      });
      return (
        <li key={index} 
            onClick={self.handleItemClick.bind(self, item)}
            className={className}>
            item.name
        </li>
      );
    });

    return (
      <ul>
        {items}
      </ul>
    );
  }
});

var items = [{
  name: 'Apple',
  value: 1
}, {
  name: 'Microsoft',
  value: 2
}];

React.renderComponent(<List items={items} />, document.body);

Question is, since the state is a reference type that holds an array of object, and in my event handler handleItemClick I only get the corresponding item. I currently mutate the item directly then call this.forceUpdate(), the result is as expected.

However as React documentation suggests, mutating the state directly is a bad behaviour, and I come across the other method that use React.addons.update to mutate a complex object, but I didn’t get it working.

So, can anyone tell me how to do this mutation properly? Thanks in advance!

React.addons.update

I could be wrong (haven’t really used React.addons.update), but I guess it looks something like

var index = this.state.items.indexOf(item);
var mutation = {}; // can't have dynamic keys in object literals :( [ yet :) ]
mutation[index] = {isSelected: {$set: true}};
var newData = React.addons.update(this.state.items, mutation);
// `mutation` looks something like
// {0: {isSelected: {$set: true}}}
// i.e. set `isSelected` of the element at index 0 to true

It would be a bit simpler if you bound the index instead of the item.

.
.
.
.