Skip to content

Instantly share code, notes, and snippets.

@sagar-gavhane
Last active August 8, 2018 14:06
Show Gist options
  • Save sagar-gavhane/19a9a00aa9bc1ecea55ffd1bd4e426e1 to your computer and use it in GitHub Desktop.
Save sagar-gavhane/19a9a00aa9bc1ecea55ffd1bd4e426e1 to your computer and use it in GitHub Desktop.
Simple infinite scrollbar with react
import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: [],
isLoading: false,
offset: 0,
limit: 10,
};
}
// single method for mutate state in app component
handleInputChange = (name, value) => {
this.setState((prevState) => {
return {
[name]: value,
};
});
};
componentDidMount() {
// fetch posts from jsonplaceholder
fetch('https://jsonplaceholder.typicode.com/posts/')
.then((res) => res.json())
.then((res) => {
// filter first ten post only
const posts = res.filter((el, i) => i < 10);
this.handleInputChange('posts', posts);
});
}
render() {
return (
<div>
<Posts
isLoading={this.state.isLoading}
posts={this.state.posts}
offset={this.state.offset}
limit={this.state.limit}
handleInputChange={this.handleInputChange}
/>
</div>
);
}
}
class Posts extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.refs.postRef.addEventListener('scroll', async () => {
const {scrollTop, clientHeight, scrollHeight} = this.refs.postRef;
// this.props.isLoading prevent from calling api multiple time holding api calls
if (scrollTop + clientHeight >= scrollHeight && !this.props.isLoading) {
const {offset, limit} = this.props;
const nextOffset = offset + limit;
await this.props.handleInputChange('offset', nextOffset);
await this.props.handleInputChange('isLoading', true);
fetch('https://jsonplaceholder.typicode.com/posts/')
.then((res) => res.json())
.then(async (res) => {
const posts = res.filter((el, i) => i <= offset);
await this.props.handleInputChange('posts', posts);
await this.props.handleInputChange('isLoading', false);
});
}
});
}
render() {
return (
<React.Fragment>
<div ref="postRef" style={{height: '400px', overflow: 'auto'}}>
{this.props.posts.length !== 0 &&
this.props.posts.map((post) => {
return (
<React.Fragment>
<h2>title: {post.title}</h2>
<p>body: {post.body}</p>
<hr />
{this.props.isLoading && <h1 style={{color: 'green'}}>Loading....</h1>}
</React.Fragment>
);
})}
</div>
</React.Fragment>
);
}
}
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
@sagar-gavhane
Copy link
Author

sagar-gavhane commented Aug 8, 2018

Play with code on codesandbox
Edit kqq5o3xnv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment