1

我在“反应虚拟化”列表中有一个交互组件,它作用于点击。单击组件时,单元格会发生变化,即高度会发生变化。

我的 rowRenderer 的第一个版本:

rowRenderer ({index, isScrolling, key, style}) {
    let message = this.props.messages[index];

    return <Message key={message.id} text={message.text} />
}

单击该消息时,会出现一个文本字段。这会改变高度。然而,发生的是组件在下一条消息上呈现。

发生这种情况是因为 UI 和 CellMeasurer 中的 Message 实例不同,如您所见:

 <CellMeasurer
    cellRenderer={
        // Here we return instance 1 
        ({ rowIndex, ...rest }) => this.rowRenderer({ index: rowIndex, ...rest })
    }
    columnCount={1}
    rowCount={messages.length}
  >

  {({ getRowHeight, resetMeasurementForRow }) => {
    this.resetMeasurementForRow = resetMeasurementForRow;

    return <List
        height={height}
        overscanRowCount={50}
        rowCount={messages.length}
        rowHeight={getRowHeight}
        rowRenderer={this.rowRenderer} // Here we create another instance
        width={width}
        ref={(ref)=>{
            this.list = ref;
        }}
    />
  }}
</CellMeasurer>

List 创建的实例显然包含正确的状态,但 CellMeasurer 不知道此状态。

我测试了以下方法,但我非常怀疑这是正确的方法吗?我只是自己缓存 UI 组件实例:

rowRenderer ({index, isScrolling, key, style}) {
    let message = this.props.messages[index];

    if(!this.componentCache[index]) {
        this.componentCache[index] = <Message key={message.id} text={message.text} />
    }

    return this.componentCache[index];
}

这解决了这个问题,但可能会引入许多其他问题。这样做的正确方法是什么?

(我知道使用 Flux/Redux/global state 可以解决这个问题,但我想知道这里是否缺少一些基本的反应虚拟化功能/方面。)

4

1 回答 1

2

对此的答案实际上在文档中:

CellMeasurer 的当前实现按需创建单元,测量它们,然后将它们丢弃。该组件的未来版本可能会尝试克隆或以其他方式与其父 Grid 共享单元格,以提高性能。但是,在此之前,请谨慎使用 CellMeasurer 来测量有状态的组件。由于单元是为测量目的而即时创建的,因此它们将仅以其默认状态进行测量。为了暂时避免这个问题,请使用受控道具(而不是状态)来进行单元格渲染行为。

所以除了处理组件外的状态,没有其他的解决方案。在实践中,我将其修复如下:

rowRenderer ({index, isScrolling, key, style}) {
    let message = this.props.messages[index];

    let selected = message.id === store.getState().selectedMessage;

    return <Message key={message.id} text={message.text} selected={selected} />
}
于 2016-12-03T11:33:03.050 回答