react-infinite-scroller
react-infinite-scroller copied to clipboard
isReverse props
i want use isReverse props but when I rendereing scroll always in top of element. So automatically load more items. How I to prevent autoload and put scroll in bottom when first load.
I've actually never used the isReverse
prop but I imagine it should be used like this:
componentDidMount() {
if(this._chatbox) {
this._chatbox.scrollTop = this._chatbox.scrollHeight;
}
}
<div
className="chatbox"
ref={c => this._chatbox = c}
>
<InfiniteScroll
...
isReverse
>
{items}
</InfiniteScroll>
</div>
I changed to ` componentDidMount(){ this.scrollToBottom(); this.setState({ hasMore : false }) }
componentDidUpdate() {
if (this.state.first) {
this.scrollToBottom();
this.setState({
hasMore : true,
first : false
})
}
}
</div>`
But I got more porblem when I scrolling to the top. The scrollbar not bounced like usual when we use without reverse.
So when scroll in top they load all data in same time not one by one .
I was just struggling with this and handle it that way:
goToPrevScroll = (oldScrollHeight) => {
const list = document.getElementById('messages-list');
list.scrollTop = list.scrollHeight - oldScrollHeight + list.scrollTop;
}
handleStackMessages = (page) => {
const list = document.getElementById('messages-list');
let oldScrollHeight = this.list.scrollHeight;
getDataFromApi.then(({ data }) => {
saveYourDataInStateOrStore(data).then(() => {
// scroll works different on firefox and chrome
if(isFirefox) {
// scroll to previous position on firefox
this.goToPrevScroll(oldScrollHeight);
} else if(list.scrollTop === 0) {
// change scrolltop to prevent loading all pages at once on chrome
this.goToPrevScroll(oldScrollHeight);
}
});
});
}
sorry for code style, I really don't understand this markdown editor.
EDIT - Fixed code style ^
@tomasz89nowak , this code is awesome!! Thank you!
One comment though, In my case I wanted to goToPrevScroll(oldScrollHeight)
every time the loadMore
fires, not only when the scrollTop === 0
Anyway, this helps alot!
@danbovey - I would consider adding something like this in Readme file, because this is the expected functionality every time you want to use isReverse
prop
That exact functionality is included in the component here https://github.com/CassetteRocks/react-infinite-scroller/blob/54d7b16a257687d6382c04300812f630cee54466/src/InfiniteScroll.js#L50-L57 it just doesn't work at the moment.
The reason it does not work is because that runs synchronously, but loadMore
(in most cases) runs asynchronously.
The only fix I can think of is requiring loadMore
to return a Promise, and then running that code in loadMore.then(() => isReverse ? fixScrollPosition() : null)
.
Hmmm... if isReverse is true, the initial scroll position should always start at the bottom (without any hacks needed). Will you accept a merge request or is this intended behaviour?
is the a demo solution for this, cause right now it keeps loading like mad, and scroll bar keeps on top. ( working with the demo files )
for me, the functionality in the component works fine (also with an async loadMore function).
However, I had massive problems on iOS Safari due to the fact that when using -webkit-overflow-scrolling: touch
it's not possible to set a scrollTop
on an element while it still has some of the "bounce". Using this fix worked for me:
if (this.props.isReverse && this.loadMore) {
const parentElement = this.getParentElement(this.scrollComponent);
parentElement.style['-webkit-overflow-scrolling'] = 'auto';
parentElement.scrollTop =
parentElement.scrollHeight -
this.beforeScrollHeight +
this.beforeScrollTop;
parentElement.style['-webkit-overflow-scrolling'] = 'touch';
this.loadMore = false;
}
em.. how to to solve this problem? I also have this pro, after loadMore the scrollbar is not correct
me too.
Is this library dead?
How to solve this problem?
My solution is:
const [hasMoreItems, setHasMoreItems] = useState(true);
const commentsRef = useRef();
const goToPrevScroll = (oldHeight = 0) => {
const { current } = commentsRef;
if (current) {
current.scrollTop = current.scrollHeight - oldHeight + current.scrollTop;
}
};
const handleFetchMessages = async page => {
const oldHeight = commentsRef.current && commentsRef.current.scrollHeight;
const { data, headers } = await fetchMessages(page);
const total = Number(headers['x-total-count']);
const totalPages = Math.ceil(total / MIN_BATCH_SIZE);
setHasMoreItems(page < totalPages);
setMessages(data.reverse().concat(messages));
if (commentsRef.current && commentsRef.current.scrollTop === 0) {
goToPrevScroll(oldHeight);
}
};
...
<div className="scroll-wrap" ref={commentsRef}>
<InfiniteScroll
pageStart={0}
initialLoad
loadMore={handleFetchMessages}
hasMore={hasMoreItems}
loader={<Loading />}
useWindow={false}
isReverse
threshold={150}
>
{messages.map(comment => (
...
))}
</InfiniteScroll>
</div>
@danbovey Why we need to use hacks for such a common use? I think i'm going to abandon this library because of this. that's a shame...
I also abandoned when I realised this functionality was missing.
I ended up using react-perfect-scrollbar with an adhoc solution.
https://www.npmjs.com/package/react-perfect-scrollbar
I'm able to get this mostly working in isReverse
mode but I've spent the last two days running into issues due to scrolling to the top too fast. The scrollbar gets "stuck" at top and future elements being loaded don't offset the scroll position as they should. Very frustrating. Abandoning this package and using react-waypoints and apollo for reverse infinite scrolling.
My solution is:
const [hasMoreItems, setHasMoreItems] = useState(true); const commentsRef = useRef(); const goToPrevScroll = (oldHeight = 0) => { const { current } = commentsRef; if (current) { current.scrollTop = current.scrollHeight - oldHeight + current.scrollTop; } }; const handleFetchMessages = async page => { const oldHeight = commentsRef.current && commentsRef.current.scrollHeight; const { data, headers } = await fetchMessages(page); const total = Number(headers['x-total-count']); const totalPages = Math.ceil(total / MIN_BATCH_SIZE); setHasMoreItems(page < totalPages); setMessages(data.reverse().concat(messages)); if (commentsRef.current && commentsRef.current.scrollTop === 0) { goToPrevScroll(oldHeight); } }; ... <div className="scroll-wrap" ref={commentsRef}> <InfiniteScroll pageStart={0} initialLoad loadMore={handleFetchMessages} hasMore={hasMoreItems} loader={<Loading />} useWindow={false} isReverse threshold={150} > {messages.map(comment => ( ... ))} </InfiniteScroll> </div>
Hello I would like to know how I could implement this same code but already receiving the data by props instead of doing a fetch
@gtaylor44, does this new library have a reverse scroll option?
React-perfect-scrollbar has props you can hook into such as: onYReachStart onScrollUp onYReachEnd
But you will still have to deal with issues that @kindmind has mentioned such as "The scrollbar gets stuck" when the user drags scrollbar to the top with mouse. You can work around the "stuck scrollbar" by having an interval that checks if scrollTop = 0 and scrollBy 1 (for top) and -1 (for bottom).
Here are some screen captures for inspiration with react-perfect-scrollbar. App attempts to load more records before user actually hits the top of scrollbar by using combination of onScrollUp prop and scrollTop position.