While reading the following article, A Quick, Practical Use Case for ES6 Generators: Building an Infinitely Repeating Array, I happened to be checking out Reddit API.
As usual, I will be lazy and refer you to these articles.
In a gist, think of it as an object that returns a sequence of data infinitely until you tell it to stop.
Here is a generator function that returns ReactJS subreddit data.
First thing to note is that, generators are declared with keyword
function* (notice the star after function).
* is what makes a function a generator.
On line#2, a URL is passed, with default value set to ReactJS API URL.
Line#4 shows a declaration of
nextUrl, which is constructed using the url from line#2 and
after argument required to fetch next batch of data (we will see it in a moment).
while loop is where the interesting things happen.
nextUrl is empty initially so it’s set to
url passed as a function argument.
Then we fetch Reddit data as JSON, which has a shape shown below.
Value stored in
after property is what we need to fetch next batch of data.
And line #10 constructs the next URL to query to fetch more data.
Thank you tills1993 for finding the bug in the previous code.
Now you might see this unfamiliar keyword
yield that returns an array of data using
Yield temporarily returns the data and gives up the control to the calling code.
So when the calling code calls
getContent again, all variables inside the
while loop is restored thus
nextUrl will contain the next URL not
(I am not sure if it’s the work of closures so I’d love to hear your feedback on it)
Lastly, we export
We’ve covered how the generator function,
getContent works so let’s move on to implement infinite scrolling in React.
Before moving on, let’s see how the end result looks visually.
It loads 4 stories with “Load More Stories” button.
Infinite scrolling will happen when the page has stories that spans longer than the view port height.
Please pardon the color combinations, I tried my best to make it pretty…
Now you see how the end result looks, let’s move on.
Let’s see the main component App’s structure.
App’s state contains all Reddit posts, and a flag to see if we have reached the bottom of the page.
repois a generator that returns Reddit data infinitely as mentioned in Generator to Return Reddit Data.
getNextPostsreturns next batch of Reddit posts (data fetch logic is hidden away in the generator function).
windowSizeHandleris a callback that’s triggered when the browser window is resized or scrolled.
componentDidMountis where we register Window Resize & Scroll events and get initial batch of Reddit posts.
componentWillUnmountis where we unregister Resize & Scroll events to remove listeners.
loadMoreStoriesis a helper function that’s called by
Load More Storiesbutton.
renderis where we load posts and shows
Load More Storiesbutton. Let’s see the implementation of each method one by one.
We register two window events and fetch initial posts to display.
I’ve used lodash.throttle function to limit the number of events generated.
Or else there will be too many events fired and make too many Reddit API requests.
spryes on reddit has pointed out that
throttle would return a new function every time so I've created a reference to the throttled implementation in
The reason for choosing
debounce is because I wanted to load next batch of data without having to wait until user started/finished scrolling/resizing.
For the difference, refer to Debouncing and Throttling Explained Through Examples.
Make sure to clean up and free up listeners when the component is unmounted.
First we calculate whether we have reached the bottom of the viewport (
window.scrollYis how much one has scrolled vertically so far
window.innerHeightis the viewport height
document.body.offsetHeightindicates the total height of the content in
If the sum of
innerHeight is same as
document.bodyOffsetHeight, then we have reached the bottom.
heightOffset value is for fetching data before reaching the bottom.
Check out the demo below, which demonstrates the usage of
We fetch next posts using the generator object instance,
💁 Note that you don’t need to pass any arguments or keep a track of next URL to call. It’s completely abstracted away.
In line#4, new posts (
posts: [...prevState.posts, ...newPosts]) are added
and turns off bottom flag since we just loaded new stories.
Here we construct reddit posts and display
Load More Stories button.
getNextPostsis asynchronous so I wrapped it in an IIFE(Immediately Invoked Function Expression) as async rendering will be available in later version.
Lastly, RedditPost component shows title and post content
And make sure you either throttle or debounce windows scroll & resize events as they fire very rapidly as explained in this post, Debouncing and Throttling Explained Through Examples.
You can get your hands dirty in two ways.