使用React的shouldComponentUpdate与Immutable.js游标

时间:2015-05-14 07:58:21

标签: javascript reactjs immutable.js

我无法弄清楚如何短路渲染分支 使用Immutable.js游标的React组件树。

采用以下示例:

import React from 'react';
import Immutable from 'immutable';
import Cursor from 'immutable/contrib/cursor';

let data = Immutable.fromJS({
  things: [
    {title: '', key: 1},
    {title: '', key: 2}
  ]
});

class Thing extends React.Component {
  shouldComponentUpdate(nextProps) {
    return this.props.thing.deref() !== nextProps.thing.deref();
  }

  handleChangeTitle(e) {
    this.props.thing.set('title', e.target.value);
  }    

  render() {
    return <div>
      <input value={this.props.thing.get('title')} 
        onChange={this.handleChangeTitle.bind(this)} />
    </div>;
  }
}

class Container extends React.Component {
  render() {
    const cursor = Cursor.from(this.props.data, 'things', newThings => {
      data.set('things', newThings);
      renderContainer();
    });

    const things = cursor.map(thing => (
      <Thing thing={thing} key={thing.get('key')} />
    ));

    return <div>
      {things}
    </div>;
  }
}

const renderContainer = () => {
  React.render(<Container data={data} />, document.getElementById('someDiv'));
};

说我改变了第一个Thing的标题。只有第一个Thing会呈现 新标题和第二个Thing将不会重新呈现 shouldComponentUpdate。但是,如果我更改了第二个Thing的标题,那么   自第二个Thing游标以来,第一个''的标题将返回Thing 仍然指向较旧版本的根数据。

我们会更新每个Container渲染上的游标,但不会更新游标 由shouldComponentUpdate引起的渲染也不会获得更新后的新光标 根数据。我可以看到保持游标最新的唯一方法是删除 此示例中shouldComponentUpdate组件中的Thing

是否有办法更改此示例以使用快速参照使用shouldComponentUpdate 平等检查,但也保持游标更新?

或者,如果不可能,您是否可以概述一下如何使用游标+ React组件并仅渲染具有更新数据的组件?

1 个答案:

答案 0 :(得分:1)

我更新了您的代码,请参阅内联评论:

class Thing extends React.Component {
  shouldComponentUpdate(nextProps) {
    return this.props.thing.deref() !== nextProps.thing.deref();
  }

  handleChangeTitle(e) {
    // trigger method on Container to handle update
    this.props.onTitleChange(this.props.thing.get('key'), e.target.value);
  }    

  render() {
    return <div>
      <input value={this.props.thing.get('title')} 
        onChange={this.handleChangeTitle.bind(this)} />
    </div>;
  }
}

class Container extends React.Component {
  constructor() {
    super();
    this.initCursor();
  }

  initCursor() {
    // store cursor as instance variable to get access from methods
    this.cursor = Cursor.from(data, 'things', newThings => {
      data = data.set('things', newThings);
      // trigger re-render
      this.forceUpdate();
    });
  }

  render() {
    const things = this.cursor.map(thing => (
      <Thing thing={thing} key={thing.get('key')} onTitleChange={this.onTitleChange.bind(this)} />
    ));

    return <div>
      {things}
    </div>;
  }

  onTitleChange(key, title){
    // update cursor to store changed things
    this.cursor = this.cursor.update(x => {
      // update single thing
      var thing = x.get(key - 1).set('title', title);
      // return updated things
      return x.set(key - 1,thing);
    });
  }
}

const renderContainer = () => {
  React.render(<Container data={data} />, document.getElementById('someDiv'));
};