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'
};
// console.log('inChat');
// console.log(inChat);
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.
Hi @EllisShen,
This looks like a pretty involved question. As the issues template suggests:
_Please don't file Github issues to ask questions._
_Use Stack Overflow (http://stackoverflow.com/questions/tagged/react-virtualized) with a #react-virtualized tag or the react-virtualized Gitter chat room (https://gitter.im/bvaughn/react-virtualized)._
I'm the only maintainer for this project (and I happen to be on vacation for the next week) so I try to redirect questions to places where they'll be seen by more people than just me. 馃槃 Thanks for understanding.
@EllisShen I had a similar symptom when upgrading a VirtualScroll to List (8.x). Make sure you pass the style property in _rowRenderer() to the parent components it returns (and that the components render() the style)
Fantastic observation, @bhj. style doesn't appear to be used- and it's vital. Thanks!
@bhj Many thanks for your advice!! I tried and so far so good! Really appreciated.
@bvaughn Maybe we should add this important info into Doc?
@EllisShen It's in the docs. 馃槃 Looks like @bhj submitted PR #428 to try to make it a little more explicit. Feel free to share if you have specific suggestions for additional things I could do to improve the docs.
Whew! I was totally having this issue. The convention of requiring the style prop to be passed along to the component returned by rowRenderer didn't click until I found this issue tracker.
Part of my confusion was that I saw this same strange behavior when I had failed to properly import the CSS when using VirtualScroll in v7.
It might be helpful to give an example where you write a rowRenderer that simply wraps an existing element in a <div>, which makes it super obvious that the style is necessary for the component to render properly.
EDIT: Oh hey, this is almost exactly what you did with the example on the List documentation. It's worth noting that I didn't even find this documentation until I investigated the merge request referenced above. The example that shows up on the front page readme is comprehensive, but a little tough to follow because it's so full of state variables.
import 'SomeComponent' from 'SomeComponent.jsx';
import { List } from 'react-virtualized';
const VirtualListExample = ({ listObjects }) => {
const render= ({ index, style }) => (
<div style={{style}}>
<SomeComponent someImportantProp={listObjects[index]} />
</div>
);
return (
<List
width={200}
height={400}
rowCount={listObjects.length}
rowRenderer={render}
rowHeight={50}
/>
);
};
Docs are hard 馃槄 The more I write, the harder it is to find any given one.
I try to provide a simplified use-case/example with each component that shows its most basic functionality. In the case of List the example would be here. I think the rowRenderer in that example fills the role you're describing?
Either way~ I happily welcome contributions to make the docs more user-friendly. I've been working with this library so long that I sometimes lose touch with common questions for people just starting out with it.
As noted above, I realized you'd posted a similar example just after I posted mine! Derp. If nothing else, maybe this conversation history will help the next person find their way there? :smile:
No problem! 馃槃 Please continue to share feedback and suggestions about the docs.
@baughn, sorry just saw your messages. I think I wasn't realized the Style was a critical key prop to making virtualscroll works properly. @bhj recent PR has greatly improved the doc, hopefully people won't encounter the same issue like me.
I think you meant @bvaughn.
On which note, bvaughn, congrats on finding an even more unique nickname, but I think mine sounds more name-like. If you wish, you may declare me your eternal nemesis.
Minor docs feedback -- the frontpage example for getting around issues with shallow-compare not detecting prop changes has this code snippet:
<List
{...virtualScrollProps}
sortBy={sortBy}
/>
Should this be changed to avoid reference to the old VirtualScroll component?
<List
{...listProps}
sortBy={sortBy}
/>
Oh no! Somebody summoned @Baughn, my arch nemesis! 馃槷 馃槀
@Nesciosquid: Reasonable docs suggestion. In the future, feel free to submit PRs with any such suggestions. I love getting docs-fixes 馃槃 I'll go ahead and make that update now though!
Not complaining, just offering one more data point: I too only discovered the "secret" style solution to the "jumping scrolling" issue through this thread (despite spending quite a long time going through the docs first).
Perhaps you could consider changing (on https://github.com/bvaughn/react-virtualized/blob/master/docs/Grid.md):
style // Style object to be applied to cell (to position it)
(which makes it sound like a meaningless property you only use if you're too stupid to write your own CSS 馃槈) to instead be:
// !!! REQUIRED !!! YOU MUST PASS THIS THROUGH !!!
style //Style object to be applied to cell (to position it)
or:
style // Style object to be applied to cell (to position it);
// this must be passed through to the rendered cell element
Similarly a few lines down perhaps:
// Style is important since it specifies how the cell is to be sized and positioned.
could be:
// Style is important since it specifies how the cell is to be sized and positioned.
// If the style is not passed through you will have strange and inexplicable behavior
// (@see https://github.com/bvaughn/react-virtualized/issues/424)
or:
// Style must be passed through since it specifies how the cell is to be sized and positioned,
// and React Virtualized depends on this sizing/positioning.
Hey @machineghost. Fair suggestion. Would you like to submit a docs PR? 馃槃
Damn that was fast! If you care to weigh in on your preference for the verbiage (I was being a little flippant in my examples) I'd be happy to.
I prefer the second style props wording and probably the second further-down note as well. Not a strong preference on the further-down note though.
https://github.com/bvaughn/react-virtualized/pull/571 has been submitted, thanks!
Most helpful comment
@EllisShen I had a similar symptom when upgrading a VirtualScroll to List (8.x). Make sure you pass the
styleproperty in _rowRenderer() to the parent components it returns (and that the components render() the style)