2016-05-25 36 views
2

我正在使用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') 
); 
+0

我不完全确定你的问题是什么问的是,正如你问过两个截然不同的问题。 – evolutionxbox

+0

这就是如果我改变行的状态:http://output.jsbin.com/hopuhuhihu – schwift

+0

你是对的,它不完全清楚......我想突出显示列表中的一些行。我的解决方案是更改我在组件中用作道具的列表。我不认为我应该这样做,但我不知道为什么。 – schwift

回答

0

如果您只渲染让我们说10了你1000的列表中的一个时间,然后要记得突出标志的唯一方法,就是将其存储在父状态,这是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的问题,“为什么是nextState == this.state”的变体,回答是“不保持状态和道具不可改变的东西了”