Reputation: 1753
am trying to implement infinite scrolling but as the component re-renders the scroll bar goes back all the way to the top as shown below. How to stick scroll bar to where user has scrolled? or is this because component re-renders? But the component has to re-render because new records are added from the api call.
AppList.tsx
//Initial values
const [pageNumber, setPageNumber] = useState<number>(1);
const [scrolling, setScrolling] = useState<boolean>(false);
const [totalPages, setTotalPages] = useState<number>(3);
<div ref={divRef} className={AppList.Container} onScroll={() => {
if (scrolling && totalPages! <= pageNumber!) {
return;
}
else {
const nodes = document.querySelectorAll('.ms-List-cell');
const lastLi: Element = nodes[nodes.length - 1];
const lastLiOffset = lastLi.getBoundingClientRect().top + lastLi.clientHeight;
const pageOffset = window.pageYOffset + window.innerHeight;
var bottomOffset = 150;
if (pageOffset > lastLiOffset - bottomOffset) {
setScrolling!(true);
setPageNumber!(pageNumber! + 1);
dispatch(GetAllAppDefinitions(dispatch, pageNumber! + 1));(Service call)
}
}
}}>
{updatedColumns.length > 0 && (
<DetailsList
className={appListTableStyle}
columns={updatedColumns}
selectionMode={SelectionMode.none}
items={updatedItems || []}
/>
)}
</div>
Upvotes: 1
Views: 4270
Reputation: 458
you can check my implementation on this medium article you don't need to use onScroll at all!
my guess is that if you bar is going to the top probably you are mounting/unmounting the component that list the items. What you would need to do is just progressively load the items. If the component that list the items stays mounted no scrolling should happen :)
Upvotes: -1
Reputation: 337
This is how I implemented my infinite scroll. scrollElement is setting in case if you scrolling on inner element instead of window
import React from 'react';
import PropTypes from 'prop-types';
componentDidMount() {
const {
initialLoad,
initialPage,
loadMore,
scrollElement
} = this.props;
(scrollElement || window).addEventListener('scroll', this.handleScroll);
if (initialLoad) {
loadMore(initialPage);
}
}
componentWillUnmount() {
const { scrollElement } = this.props;
(scrollElement || window).removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
const {
loadMore, threshold, hasMore, loading, page, scrollElement
} = this.props;
if (scrollElement) {
const contentHeight = document.getElementById('scroller').clientHeight;
const { scrollTop } = scrollElement;
const { y, height } = scrollElement.getBoundingClientRect();
if (((height - y) + scrollTop) > contentHeight - threshold && hasMore && !loading) {
loadMore(page);
}
return;
}
const { innerHeight, scrollY } = window;
const contentHeight = document.getElementById('scroller').clientHeight;
if (innerHeight + scrollY > contentHeight - threshold && hasMore && !loading) {
loadMore(page);
}
};
render() {
const {
loading, children, loader, className
} = this.props;
return (
<div
id="scroller"
className={ className }
>
{ children }
{ loading ? loader : null }
</div>
);
}
}
Upvotes: 1
Reputation:
Here is a basic example of infinite scrolling using React Hooks, you can modify it according to your need to make an API request and push it to your data,
import React, { useEffect, useState, useRef } from 'react';
const divStyle = {
color: 'blue',
height: '250px',
textAlign: 'center',
padding: '5px 10px',
background: '#eee',
marginTop: '15px'
};
const containerStyle = {
maxWidth: '1280px',
margin: '0 auto',
}
const InfiniteScroll = () => {
const [postList, setPostList] = useState({
list: [1,2,3,4]
});
// tracking on which page we currently are
const [page, setPage] = useState(1);
// add loader refrence
const loader = useRef(null);
useEffect(() => {
var options = {
root: null,
rootMargin: "20px",
threshold: 1.0
};
// initialize IntersectionObserver
// and attaching to Load More div
const observer = new IntersectionObserver(handleObserver, options);
if (loader.current) {
observer.observe(loader.current)
}
}, []);
useEffect(() => {
// here we simulate adding new posts to List
const newList = postList.list.concat([1,1,1,1]);
setPostList({
list: newList
})
}, [page])
// here we handle what happens when user scrolls to Load More div
// in this case we just update page variable
const handleObserver = (entities) => {
const target = entities[0];
if (target.isIntersecting) {
setPage((page) => page + 1)
}
}
return (<div className="container" style={containerStyle}>
<div className="post-list">
{
postList.list.map((post, index) => {
return (<div key={index} className="post" style={divStyle}>
<h2> {post } </h2>
</div>)
})
}
<!-- Add Ref to Load More div -->
<div className="loading" ref={loader}>
<h2>Load More</h2>
</div>
</div>
</div>)
}
export default InfiniteScroll;
Credits to => https://dev.to/hunterjsbit/react-infinite-scroll-in-few-lines-588f
Upvotes: 2