基本上,我们结束了使用深度对比来确保改变的正确跟踪,这个方法在性能上的花费是很大的,因为我们需要为每个 model 写不同的深度对比代码。算这样,如果我们没有处理好对象引用,它甚至不能工作,比如说这个父组件:
  React.createClass({
  getInitialState: function() {
  return { value: { foo: 'bar' } };
  },
  onClick: function() {
  var value = this.state.value;
  value.foo += 'bar'; // ANTI-PATTERN!
  this.setState({ value: value });
  },
  render: function() {
  return (
  <div>
  <InnerComponent value={this.state.value} />
  <a onClick={this.onClick}>Click me</a>
  </div>
  );
  }
  });
  内部组件第一次渲染的时候,它会获取 { foo: 'bar' } 作为 value 的值。如果用户点击了 a 标签,父组件的 state 会更新成 { value: { foo: 'barbar' } },触发内部组件的重新渲染过程,内部组件会收到 { foo: 'barbar' } 作为 value 的新的值。
  这里的问题是因为父组件和内部组件共享同一个对象的引用,当对象在 onClick 函数的第二行发生改变的时候,内部组件的属性也发生了改变,所以当重新渲染过程开始,shouldComponentUpdate 被调用的时候,this.props.value.foo 和 nextProps.value.foo是相等的,因为实际上 this.props.value 和 nextProps.value 是同一个对象的引用。
  因此,我们会丢失 prop 的改变,缩短重新渲染过程,UI 也不会从 'bar' 更新到 'barbar'
  Immutable-js 来救赎
  Immutable-js 是 Lee Byron 写的 JavaScript 集合类型的库,近被 Facebook 开源,它通过结构共享提供不可变持久化集合类型。一起看下这些特性的含义:
  Immutable: 一旦创建,集合不能再改变。
  Persistent: 新的集合类型可以通过之前的集合创建,比如 set 产生改变的集合。创建新的集合之后源集合仍然有效。
  Structural Sharing: 新的集合会使用尽量多的源集合的结构,减少复制来节省空间和性能友好。如果新的集合和源集合相等,一般会返回源结构。
  不可变让跟踪改变非常简单;每次改变都是产生新的对象,所以我们仅需要对象的引用是否改变,比如这段简单的 JavaScript 代码:
  var x = { foo: "bar" };
  var y = x;
  y.foo = "baz";
  x === y; // true
  尽管 y 被改变,因为它和 x 引用的是同一个对象,这个对比返回 true。然而,这个代码可以使用 immutable-js 改写如下:
  var SomeRecord = Immutable.Record({ foo: null });
  var x = new SomeRecord({ foo: 'bar'  });
  var y = x.set('foo', 'baz');
  x === y; // false
  这个例子中,因为改变 x 的时候返回了新的引用,我们可以安全的认为 x 已经改变。
  脏检测可以作为另外的可行的方式追踪改变,给 setters 一个标示。这个方法的问题是,它强制你使用 setters,而且要写很多额外的代码,影响你的类。或者你可以在改变之前深拷贝对象,然后进行深对比来确定是不是发生了改变。这个方法的问题是,深拷贝和深对比都是很花性能的操作。
  因此,不可变数据结构给你提供了一个高效、简洁的方式来跟踪对象的改变,而跟踪改变是实现 shouldComponentUpdate 的关键。所以,如果我们使用 immutable-js 提供的抽象创建 props 和 state 模型,我们可以使用 PureRenderMixin,而且能够获得很好的性能增强。
  Immutable-js 和 Flux
  如果你在使用 Flux,你应该开始使用 immutable-js 写你的 stores,看一下 full API。
  让我们看一个可行的方式,使用不可变数据结构来给消息示例创建数据结构。首先我们要给每个要建模的实体定义一个 Record。Records 仅仅是一个不可变容器,里面保存一系列具体数据:
  var User = Immutable.Record({
  id: undefined,
  name: undefined,
  email: undefined
  });
  var Message = Immutable.Record({
  timestamp: new Date(),
  sender: undefined,
  text: ''
  });
  Record 方法接收一个对象,来定义字段和对应的默认数据。
  消息的 store 可以使用两个 list 来跟踪 users 和 messages:
  this.users = Immutable.List();
  this.messages = Immutable.List();
  实现函数处理每个 payload 类型应该是比较简单的,比如,当 store 看到一个代表新消息的 payload 时,我们创建一个新的 record,并放入消息列表:
  this.messages = this.messages.push(new Message({
  timestamp: payload.timestamp,
  sender: payload.sender,
  text: payload.text
  });
  注意:因为数据结构不可变,我们需要把 push 方法的结果赋给 this.messages。
  在 React 里,如果我们也使用 immutable-js 数据结构来保存组件的 state,我门可以把 PureRenderMixin 混入到我门所有的组件来缩短重新渲染回路。