Ellis Shen
Ellis Shen

Reputation: 227

VirtualScroll (List) with dynamic item height scrolling not smooth and jumping

I have been tuning the VirtualScroll (List) component for almost whole day but no luck.

I'm building a web based chatting application in which uses the react-virtualized List to display the chatting messages. Since message may have different content and different height, I use react-measure to calculate the item height and issue the recomputeRowHeights in rowRenderer.

The result is bad, VirtuallScroll List will jump around whenever I stopped the scrolling. For example, when I scrolled to the half of browser, I should see the middle of the messages, but it always suddenly shift the offset. Please take a look at the recorded video: https://drive.google.com/file/d/0B_W64UoqloIkcm9oQ08xS09Zc1k/view?usp=sharing

Since I only use the List and Autosizer component, I only adapt the required css file into my project which is like ```

.VirtualScroll {
    width: 100%;
    outline: none;
}

```

For the render method, I nested a lot of flex components inside the rowRender: Here is the code:

```

render() {
    const inChat = this.context.store.getState().inChat;
    const {conversationList} = this.state;
    const imgUrl = 'img/builtin-wallpaper-1.jpg';
    const backgroundStyle = {
        backgroundImage: 'url(' + imgUrl + ')',
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'cover',
        backgroundPosition: 'top left'
    };

    if (inChat.id === this.id && inChat.status === 'FETCHING'){
        return (
                <Box column center height="80%">
                    <CircularProgress />
                </Box>
        );
    } else if (inChat.id === this.id && inChat.status === 'FETCHED'){
        return (
                <Box column flex="1 0 100%" style={backgroundStyle}>
                    <HorizontalToolBar/>
                    <AutoSizer disableHeight={true}>
                        {({ width }) => (
                                <List
                                        ref={(element) => {this.VirtualScroll = element;}}
                                        className='VirtualScroll'
                                        height={window.innerHeight - toolbarHeight - textAreaHeight}
                                        overscanRowCount={10}
                                        noRowsRenderer={this._noRowsRenderer.bind(this)}
                                        rowCount={conversationList.length}
                                        rowHeight={i => {
                                    return (Measured_Heights[i.index] | 20);  // default Height = 58
                                }}
                                        rowRenderer={this._rowRenderer}
                                        scrollToIndex={undefined} // scroll to latest item
                                        width={width}
                                />
                        )}
                    </AutoSizer>
                    <InputControl chatId={this.id} sendChatText={this._sendChatText.bind(this)}/>
                </Box>
        );
    } else {
        return null;
    }
}

_rowRenderer ({ index, key, style, isScrolling }) {
    console.log(Measured_Heights);

    const rowData = this._getDatum(index);
    // let renderItem;

    // console.log('index = ' + index + ' key = ' + key);

    if (rowData.type == 'conversation') {

        if (rowData.data.type == netModule.TYPE_SYSTEM) {
            // system message
            return (
                    <Measure key={key} onMeasure={(dims) => this._onMeasure(index, dims)}>
                        <SystemMessage data={rowData.data}/>
                    </Measure>
            )
        }

        if (rowData.data.senderId == this.state.selfProfile.username) {
            // outgoing message
            return (
                    <Measure key={key} onMeasure={(dims) => this._onMeasure(index, dims)}>
                        <RightMessage
                                screenWidth={(window.innerWidth - leftToolBarWidth) / 2 }
                                screenHeight={window.innerHeight - toolbarHeight}
                                data={rowData.data}/>
                    </Measure>
            );

        } else {
            // incoming message
            // append userProfile to left messages
            return (
                    <Measure key={key} onMeasure={(dims) => this._onMeasure(index, dims)}>
                        <LeftMessage
                                userId={rowData.data.senderId}
                                userProfile={this.state.groupUserProfiles[rowData.data.senderId]}
                                screenWidth={(window.innerWidth - leftToolBarWidth) / 2 }
                                screenHeight={window.innerHeight - toolbarHeight}
                                data={rowData.data}/>
                    </Measure>
            );
        }
    }
}

```

I read a couple docs that Flexbox may be intercept the scrolling event, but even though I added overflow-y: hidden to nested component I didn't see the issue disappear. Have you ever seen this wrong scrolling behavior with List component before?

Any suggestion is welcome.

Upvotes: 0

Views: 1860

Answers (1)

fauxparse
fauxparse

Reputation: 11

I can't see the video, but I think I had something similar recently. From what I can see, you're not making use of the style parameter passed into your _rowRenderer method. This parameter contains some CSS transforms that make the row appear at the right vertical position in the scrolling list.

Upvotes: 1

Related Questions