1

I have an interactive component inside "react-virtualized" List that acts on clicks. When the component is clicked, the cell transforms i.e. height changes.

My first version of the rowRenderer:

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

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

When the message is clicked, a text field appears. This changes the height. What however happens is that component renders over the next message.

This happens because the instance of Message is different in UI and in CellMeasurer as you can see:

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

The instance created by List will obviously contain correct state but CellMeasurer is not aware of this state.

I tested the following approach but I highly doubt that this is the correct way to do this? I simply cache the UI component instance myself:

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];
}

This fixes this problem but probably introduces many other issues. What is the correct way to do this?

(I'm aware that using Flux/Redux/global state could fix this but I'm wondering is there some fundamental react-virtualized feature/aspect that I'm missing here.)

4

1 に答える 1