如何正确使用Ce​​llMeasurer?

How to use CellMeasurer correctly?

我在 "react-virtualized" 列表中有一个交互组件,它作用于点击。单击组件时,单元格会发生变化,即高度发生变化。

我的第一个 rowRenderer 版本:

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

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

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

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

 <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 状态可以解决这个问题,但我想知道这里是否缺少一些基本的反应虚拟化 feature/aspect。)

这个问题的答案实际上在文档中:

The current implementation of CellMeasurer creates cells on demand, measures them, and then throws them away. Future versions of this component may try to clone or in some other way share cells with their parent Grid in order to improve performance. However until that happens, be wary of using CellMeasurer to measure stateful components. Since cells are just-in-time created for measuring purposes they will only be measured with their default state. To avoid this issue for now, use controlled props (instead of state) for cell rendering behavior.

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

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} />
}