不变性有什么好处?

时间:2016-05-25 08:52:33

标签: javascript reactjs immutability

我正在使用React渲染长的可滚动项目列表(+1000)。我发现React Virtualized可以帮助我。

所以看example here我应该将列表作为道具传递给我的项目列表组件。让我感到震惊的是,在示例中,列表是不可变的(使用Immutable.js)我认为这是有意义的,因为道具应该如何工作 - 但如果我想对行项目进行更改我不能更改其状态,因为该行将使用列表重新呈现,从而丢弃状态。

我要做的是在我点击它时突出显示一行,如果我滚出视图并再次返回该视图,它仍然会突出显示。现在,如果列表不是不可变的,我可以更改表示行的对象,突出显示的行将保持突出显示,但我不确定这是正确的方法。除了改变道具之外,还有解决方法吗?

class ItemsList extends React.Component {
  (...)
  render() {
    (...)    
    return(
      <div>
        <VirtualScroll
          ref='VirtualScroll'
          className={styles.VirtualScroll}
          height={virtualScrollHeight}
          overscanRowCount={overscanRowCount}
          noRowsRenderer={this._noRowsRenderer}
          rowCount={rowCount}
          rowHeight={useDynamicRowHeight ? this._getRowHeight : virtualScrollRowHeight}
          rowRenderer={this._rowRenderer}
          scrollToIndex={scrollToIndex}
          width={300}
        />
      </div>
    )
  }
  _rowRenderer ({ index }) {
    const { list } = this.props;
    const row = list[index];

    return (
      <Row index={index} />
    )
  }
}


class Row extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      highlighted: false
    };
  }

  handleClick() {
    this.setState({ highlighted: true });

    list[this.props.index].color = 'yellow';
  }

  render() {
    let color = list[this.props.index].color;

    return (
      <div 
        key={this.props.index}
        style={{ height: 20, backgroundColor: color }}
        onClick={this.handleClick.bind(this)}
        >
        This is row {this.props.index}
      </div>
    )
  }  
}

const list = [array of 1000+ objects];

ReactDOM.render(
  <ItemsList
    list={list} 
  />,
  document.getElementById('app')
);

1 个答案:

答案 0 :(得分:0)

如果你只渲染让我们一次从你的1000个列表中说出10个,那么记住highlight-flag的唯一方法就是将它存储在父状态,这是1000的列表

没有不变性,这就像是:

// make a copy of the list - NB: this will not copy objects in the list
var list = this.state.list.slice();    
// so when changing object, you are directly mutating state
list[itemToChange].highlighted = true; 
// setting state will trigger re-render
this.setState({ list: list });
// but the damage is already done: 
// e.g. shouldComponentUpdate lifecycle method will fail
// will always return false, even if state did change.

凭借不变性,你会做一些非常相似的事情:

// make a copy of the list
var list = this.state.list.slice();
// make a copy of the object to update
var newObject = Object.assign({}, list[itemToChange]);
// update the object copy
newObject.highlighted = true;
// insert the new object into list copy
list[itemToChange] = newObject;
// update state with the new list
this.setState({ list : list );

以上仅在对象不包含更多嵌套对象时才有效 我不熟悉immutable.js,但我确信他们有更好的方法可以更恰当地处理这个问题。

反应不变性的论点是,你可以可靠而透明地处理状态变化(也就是反应的生命周期方法期望它们)。关于SO的变体有很多问题&#34;为什么nextState == this.state&#34;,答案归结为&#34;不保持状态和道具不可变的搞砸事情&#34;

相关问题