After a long discussion in #143 I also took a shot at this problem and arrived to the following solution:
import React, { Component } from 'react';
import { Scrollbars } from 'react-custom-scrollbars';
import { List } from 'react-virtualized';
const SCROLL_DIRECTION_BACKWARD = -1;
const SCROLL_DIRECTION_FORWARD = 1;
const SCROLL_POSITION_CHANGE_REASON_OBSERVED = 'observed';
const listStyle = {
overflowX: false,
overflowY: false,
};
export default class SmartList extends Component {
_getScrollDirection(scrollTop) {
const {
scrollTop: oldScrollTop,
scrollDirectionVertical,
} = this.List.Grid.state;
if (scrollTop !== oldScrollTop) {
return scrollTop > oldScrollTop ?
SCROLL_DIRECTION_FORWARD :
SCROLL_DIRECTION_BACKWARD;
}
return scrollDirectionVertical;
}
handleScroll = ({ target }) => {
const {
scrollTop,
scrollLeft,
} = target;
const { Grid: grid } = this.List;
grid._debounceScrollEnded();
const scrollDirectionVertical = this._getScrollDirection(scrollTop);
const totalColumnsWidth = grid._columnSizeAndPositionManager.getTotalSize();
const totalRowsHeight = grid._rowSizeAndPositionManager.getTotalSize();
grid.setState({
isScrolling: true,
scrollDirectionVertical,
scrollTop,
scrollPositionChangeReason: SCROLL_POSITION_CHANGE_REASON_OBSERVED,
});
grid._invokeOnScrollMemoizer({ scrollLeft, scrollTop, totalColumnsWidth, totalRowsHeight });
};
List = null;
render() {
const { width, height } = this.props;
return (
<Scrollbars
autoHide
style={{ width, height }}
onScroll={this.handleScroll}
>
<List
{...this.props}
ref={instance => (this.List = instance)}
style={listStyle}
/>
</Scrollbars>
);
}
}
You can see that I've pretty much rewritten the _onScroll method in https://github.com/bvaughn/react-virtualized/blob/master/source/Grid/Grid.js#L1110
The simplest way to make this work will be to add a way to bypass the container node check in _onScroll.
@bvaughn what do you think?
I don't understand this comment on #143:
@bvaughn can you maybe add a second parameter to _onScroll that let you pass event from another container?
_onScroll (and _invokeOnScrollMemoizer) are private- not intended to be called by external code.
I guess Grid could be refactored to add a new handleScroll({ scrollLeft, scrollTop }) method that _onScroll calls internally but could also be called externally. This would avoid the node-check.
If you'd like to submit a PR I'll review it.
@bvaughn ah, yes, you're right about that one. brb 馃憤
@bvaughn I'm a bit concerned that test don't pass even without my changes 馃
Did you yarn install or npm install ?
This is a fresh system, so I installed latest node an run npm install. And it failed too, yeah. Should I try yarn?
Use yarn install
@bvaughn 馃憣 Yup, it works now, thanks.
馃槄 Glad to hear
For anyone who struggles with handleScrollEvent and doesn't understand how it is related to the code snippet above, here how it all looks with the new method. @5angel tons of :+1: to you
import React, { Component } from 'react';
import { Scrollbars } from 'react-custom-scrollbars';
import { List } from 'react-virtualized';
const listStyle = {
overflowX: false,
overflowY: false,
};
export default class SmartList extends Component {
handleScroll = ({ target }) => {
const { scrollTop, scrollLeft } = target;
const { Grid: grid } = this.List;
grid.handleScrollEvent({ scrollTop, scrollLeft });
}
List = null;
render() {
const { width, height } = this.props;
return (
<Scrollbars
autoHide
style={{ width, height }}
onScroll={this.handleScroll}
>
<List
{...this.props}
ref={instance => (this.List = instance)}
style={listStyle}
/>
</Scrollbars>
);
}
}
Hi, may I ask for help with solution from @alexpyzhianov? The method handleScrollEvent when fires and updates Grid component causes lags on scrolling. The method handleScrollEvent was bombed by scrolling events so I tried to reduce them by calling it only for scrolls of certain height. It wasnt so laggy, but still each call cause lag on scroll. Next step I tried was to call it in setTimeout to force run it in a new thread (I was desperated) - same result. Any ideas?
@evercool have you found solution?
Maybe another solution, it works for me:
````js
import React from 'react';
import { Scrollbars } from 'react-custom-scrollbars';
import { List, AutoSizer } from 'react-virtualized';
export class DemoList extends React.Component {
handleScroll = (e) => {
this.list.Grid._onScroll(e);
}
componentDidMount = () => {
this.list.Grid._scrollingContainer = this.scroll.view;
}
render() {
return (
{({ height, width }) => (
{...this.props}
style={{ overflowX: 'visible', overflowY: 'visible' }}
ref={node => this.list = node}
height={height}
/>
)}
);
}
}
````
@evercool @borovik96 I'm having a similar problem. Trying to use react-custom-scrollbars instead of ScrollSync to avoid lag problem but the onScroll callback is called for API updates as well so on scroll, the natural event fires, which I use to call scrollTop(y) on the partner Scrollbars instance, but then it triggers onScroll on the other instance and fires it back, etc etc. react-custom-scrollbars does not differentiate API events from user events unfortunately... Any ideas?
Can this technique be used with the table and would it let the headers be fixed and only scroll the data?
Most helpful comment
For anyone who struggles with
handleScrollEventand doesn't understand how it is related to the code snippet above, here how it all looks with the new method. @5angel tons of :+1: to you