Infinite Scrolling With React - Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everyone in today's video we're gonna create a react application that has infinite scrolling built into it and we're gonna actually use quite a few interesting features of react such as refs and creating our own custom hooks it's going to be a ton of fun so let's get started now welcome back to web dev simplified my name is Kyle and my job is to simplify the web for you so if that sounds interesting make sure you subscribe to my channel for more videos just like this one and to get started on the left hand side I have Visual Studio code open and all I did was run npx create react app with a period and this generated all of the boilerplate react code that we're going to need I then went around and removed all the files we don't need such as CSS files and such as serviceworkers and test files so that were just left with our index J s and an empty app file to actually put all of our react code inside of also on the right I have the finished version of our application all we do is search here for some form of book that we want this is going to query a book API so we can type in test for example and you can see we get a bunch of different results and when we get to the bottom of the page you see it says loading right there and then it'll load in our results and you can just continually scroll down until we get to the very end of all of our results this was just infinitely scroll until there's no more books with the name test inside of their title also something this will do is if we scroll all the way back to the top and do a different search for example for your search for TE you see it'll reset our pagination so that we start all over with our infinite scroll again from the beginning and it will clear out all of our old search results for us so in order to get started let's actually just create the basic JSX template for our application and we can do that inside of our app here the first thing that we're going to have is we're going to have an input component so let's create an input this is going to be a type of text and this is actually going to be here this input right here after that we're going to return some other stuff so let's put this inside of fragments so we can return but multiple sets of HTML inside of our JSX there we go and here is where we're going to put our books they're going to be in a div and amber you're going to have the title let's just copy that down a couple times so that we have an example of what this is going to look like and then lastly we're going to have a div which is going to contain loading for one more and if we have an error we're gonna have a dip which is going to contain error so let's save that and actually start our application just run npm run start and if we let that run for just a little bit you see it's going to start up over on the side here and there you go you can see that we have our boilerplate HTML being generated for us and that we can actually work on implementing the api and infinite scrolling inside of our application and to do that we're going to use Axios to call our api so let's install access by typing in npm i followed by Axios and this will install the library access force which works a lot like the fetch library does but it's much easier to use rather than fetch which can be a bit difficult to use and isn't supported in all browsers now that we have that done we could do all of our code inside of our app for rendering our books actually query in them using Axios and doing all that other stuff but with react and hooks it's a lot easier to break out our logic into a custom hook so we're going to create a custom hook called use book search jeaious and inside of here we're gonna create a functional component and if you have the extension installed which is called es7 react Redux graph QL blah blah blah snippets you can just type RFC and hit enter and it will generate all the boilerplate code for you for a function component in react which is also the same boilerplate code for actually generating a custom hook we can just remove the JSX because we're not actually going to return JSX and we also no longer need to import react but we do want to import use effect just like that which is going to be the hook that we're going to be using inside of our custom hook because we want to call our API and that's enough side effect that we want to call every single time some parameters change we also want to make sure that we have the used state hook because we're going to be storing state inside of this custom hook which we then expose outside of this custom hook by returning it down here in this return for now we'll just return null and inside of this component what we need to do is query that API like I mentioned but we need to take in a few parameters for what we're querying the first thing we want to take in is the query essentially whatever we type into this text box here we want to send to our search we also want to send in here what page number were on because while we are doing infinite scrolling the way that infinite scrolling works is as soon as you get to the bottom of your list of results it'll query the next page of results from the API and append it on to the bottom of our page so we need to know what page number we're currently trying to get from the API and once we have those two pieces of information we can actually set up access inside of an effect so we can just say here use effect this is going to take a function which is what we're going to do every single time that the parameters inside of this array which is the second argument to use affect change and in our case we want this to happen every time our query or our page number change and inside of here we can use access to get our information what's first import Axios from access and we just want to say Axios and this is just a function which is going to take all the parameters that we need to give it so for example a method this is going to be a get request we also need to give it a URL I'm just going to copy this URL from the API we're using essentially this is the Open Library API and we're using the Search API that they have built in which has pagination built into it so we can pass that as our params so the first thing is our query and in this case they call that / mq in the API so we're gonna pass Q as query and we also need to pass page which is just our page number variable and these are things you can find in the API documentation for this API but for our example Q is our query and page is the page number that we're on inside of our query also with Axios this is going to be a promise based thing so we can just use Ben and this first dot then here is going to return us our response so we have a response variable and then we can actually do something with that response and the data of our response is instead of res data and this data we can just console that log this for now and we'll take a look at what this looks like so that we can actually understand what our data is doing so now back inside of our app let's import that hook so we can say import use look search we want to import that from our dot slash use book search so now we actually have this hook inside of our application and we can actually use this hook for example we want to pass it our query and we want to pass it our page number which right now we don't have stored anywhere so we need to store these inside of state so up here we can just import that used state hook which will allow us to create some state and the first thing we can do is set up state for our query so we have query and set query now we're going to set this here equal to use state and by default our query is just going to be an empty string and this use state function returns a query as well as a function to set that query which is going to rerender our application let's copy this down and do the same thing for our page number as well as for setting our page number and by default we're just going to have page number one for when we load our application now we actually have these variables being set but we're not updating them anywhere the easy one to update is our query so we can just update that in our input we can set a non change event to this and we can just say and here we want to call a function called handle search that we can create that function just like this so let's say handle search and this is going to take the event and then it's going to actually do some stuff with that vent which is going to be setting our query so we can say set query and we want to set that to e target dot value and this is just going to be the value of whatever is in this search box we also want to set our page number back to 1 because every time we we query we want our data results to start at the very first page we don't want them to start at page 7 if we do a new query now that that's all done let's actually save this inspect our page over here and make sure this is working as we expect if we go into the console zoom this in a little bit you can see that we first are getting an object for our blank results but if we query test we should here you see get a bunch of results and this is because we're not cancelling our previous requests so every character that we type is actually sending off a request because every character we type causes this function to run which updates our query which then updates our search so we're going to fix that in a little bit but what I do want to look at is the actual results we get returned as you can see this data has a Doc's field which is all of the different books that we are querying you can see it's a very long list and inside of here we also have the number of results found as as the start so this is what page were currently on so for example start zero its page one and then whatever our pagination number is which in this case I think is a hundred so start one hundred would be page number two and this num found is going to be really useful for what we know when to end our entire scrolling but to get started let's worry about this cancellation because we don't want to send a query every single time we want to cancel our old query if we are typing information so in our use book search here Axios has a really easy way to set up cancellations it takes a parameter called cancel token and this cancel token is equal to Axios whoops Axios dot cancel token and we want to create a new one of these and this is actually capital cancel here and inside of this cancel token it's just going to take a function and this function takes a single parameter which is going to beat the cancel token and we want to set our own variable to that so let's create a variable called the cancel and now we're going to be setting that variable cancel here to the C from our cancel token essentially this is allowing us to cancel our request and what we can do instead of user fact is if you return something from use effect you return a function and then inside that function we can just call cancel and this is going to cancel our request every single time it recalls a use effect so now let's save that and we can start typing inside of here and you can see that immediately we're getting uncaught promises because every single time that we cancel something it causes a error to occur instead of our promise so let's actually catch that we can say inside of here we want to catch our error and what we want to do is we want to check to see if this is an Axios cancellation error so luckily inside Axio so they have built in a really easy way to say is cancel we just pass it our error and if so we just want to return essentially we're saying ignore every single time that we can still request because we meant to cancel it now if we say that and go over here and start typing you'll see that only one request is made no matter how many characters we type it's only going to send that one single request and it's not going to send a bunch of extra requests because it's actually cancelling those for us which is really great also inside of this catch we can return any errors we get so we can actually notify the user of errors so now start setting up the state inside of our use book search so we can return this because right now this does nothing it's just returning no and login to the console but we actually want to return data to our user from this so we can set up our state and we're going to have a few different things of state the first thing we're gonna have is loading so we want a safe for loading as well as a way to set loading and we can say use state and of course by default we're gonna set our loading to true because the very first thing we're gonna do is load inside of our application next we're going to set up a error as well as set error and by default we're not going to have an error so we're just gonna set that to false the last two pieces of state is we're gonna have our state for our books this is pretty self-explanatory this is the actual books we get back from our API call and we want this just be an empty array to start with because we have no books being found and then a little bit more confusing piece of state we want is a has more as well as set has more and we're gonna set this here to you state and by default we're just gonna set that to false just in case there is no more results and this has more essentially is telling us when we get to that number seventy nine thousand results if we somehow scroll through all of those we don't want to keep making a request to the API because there is no more results so this will essentially prevent us from making a request that we don't really want to make now that we have all of our state set up let's actually start setting the state inside of our application so the first thing we want to do is every time we make a request we want to set loading to be true because we are now loading and we want to set our error to be false because we no longer have an error because we're starting a brand new request which hopefully will succeed instead of fail also inside of our dot then here we can set our state for our books so we can say set books and this is actually going to be using the function version of setting state which allows us to take the previous state which in our case is previous books so we can actually modify our previous books and what we want to do is we want to return our previous books combined with our new books so we could say previous books and we want to spread that as well as we want to add in here our new books which is going to be our res data dot Docs as you can see over here we have open this this is going to be our books and we want to map over that because we just want the title of our books so we're gonna have a book here we just want to get B dot title because this is the title of our book and we don't care about anything else one thing to note though is that this actually is going to return to us a list of variables where we could have multiple titles because this data actually does things beyond just the title of the book it actually has editions and other things so it may have multiple titles that are exactly the same and we want to remove those and a really easy way to do that is which what's called a set essentially a set in JavaScript you can pass it an array and it's going to return just unique values it's not going to return any of the other information so we're gonna have only the unique titles and all we need to do is convert this back to an array by just spreading over our entire set it's a little bit confusing but essentially what we're doing is we're combining our old books with our new books and then we're converting it to a set so we will remove all the duplicates and then we're converting it back to an array so we can do all of our normal array manipulation such as looping and mapping that we want to do later so now that we have our book set let's also set our has more and has more is going to be pretty simple we just want to check here if the res data flips data Docs length is greater than 0 which essentially means that we have no more data because there's no books returned to us so we know that we never need to make this query again also we can set our loading here to false because we're no longer loading our data also inside of our catch we want to set our error to be true because we actually do have an error that is coming from our results something went wrong with our API so we want to make sure we make note of that and now that we have all these different variables being set we can actually return these to our user so down here in our return we can return an object and this object is going to contain loading it's going to contain error books as well as has more so now all of the state from our hook is being returned from this hook and we can use it inside of our app so now here we can say that we want a constant variable it's going to be equal to this and we're just going to destructor out our books or has more we're going to be structure out loading as well as air so now we have all the different variables from our use book search that we have available inside of our application and we can actually start rendering some of this information for example we can come in here and actually render out our books so we can say books dot map so we can loop over all of our books and for each book what we want to do is we just want to call a function here and this function is just going to print out a div so we can just say return div we need to give it a key because in react when you ever you render a list of items from an array you need a unique key which in our case we're just gonna put our book in there because these are the titles of our book and we know they're unique since we use that set property to make sure we only return two unique books and then we can just put the name of the book in here as well also our loading we can put in if we are loading then we want to put the text of loading dot dot and let's just copy this down the exact same thing for air but instead we're gonna say air and we can remove this air down here and now if we save this close out of this console and we just type in test for example you can see us as loading and then we get the list of all of our different books but you will notice our books aren't quite being structured right and that's because in our used book search I forgot to actually spread out our results so now if we save this and do a new search for test you should see we're getting all of our results perfectly in here but of course there's no pagination setup yet but that's okay we're gonna work on that now but there's still one bug if we scroll back up to the top and let's say we change our query to be just tea or tea there we go and now you can see that our results aren't actually being appended on to the end we have all of our tea results as well as our test results so what we need to do inside of our use book search is use another effect and this effect is going to be a very small effect and all it's going to do is every single time that we change our query we're gonna set here our books so we're going to say set books we just want to set it back to an empty array so every time we change our query we're gonna reset our book array so that we don't have any of our old books being shown up now if we save this search for test you see we get all of our test results if we change it to tea you can see we're just going to get our tea results back which is perfect now with all that out of the way we finally work on the part that you've been waiting for which is setting up pagination so if we go back to our app here one thing that I forgot to do is set our value here whoops of value to our query so let's just make sure we do that that way just in case we change our query somewhere else it'll be updated inside of this input field also to set up pagination we need to use what are called with refs inside of react so we can just come in here and say use whoops ref and a ref is essentially a value that persists after each render because inside of react every single thing that we do is only stored inside that render unless it's part of our state but if we want to store something between renders that isn't part of our state we need to use ref and ref is really great when you need to store references to elements for example if we want to get a reference to our books element or an input element or if you want to get a reference to something that's related to the document API and in our case we're using intersection observer which is part of the document API so let's create a variable what you're going to do it all the way up here we're going to say Const observer is going to be equal to use ref just like that and by default the first time this gets ran issue is going to have undefined as the value which is okay we also need to get a reference to the very last book element because what we're going to do is we're gonna make it so that when we scroll all the way down and that our very last book element in our case Scandinavian cooking is shown on the screen then we actually want to change our page number and add one to it so intersection observer is going to allow us to say when something's on our screen but we need to get an element reference to that very last element in our books array in order to know which element is the last one and you would think we could just do this with use ref but like I mentioned use ref is not part of our state so it doesn't update every single time that it changes so when our reference changes it doesn't actually rerun our component so what we're going to use is you use callback and this actually has a really unique interaction with users ref where if we set a ref for example if we said ref is equal to and we used a use ref so if I just come up here and say Const last book element ref and I set it equal to use callback and I actually supplied information here we could set that reference down here and now what's gonna happen is whenever this element is created it's going to call the function instead of use callback with the reference to the element that we're using down here so it's gonna call a function which is going to have node for example as the parameter and this node corresponds to this individual element right here but we only want to do this for our very last book so let's put in a simple if check here and we can just say that if our books dot length is equal to index plus one and we can just use the index inside of our map like this we can say index is the second property to map so if for example our length of our books is equal to our index plus one essentially this is the very last book then what we want to do is we want to return this because we want to get reference to that very last book otherwise if it's not the last book we want to do almost the exact same thing but we no longer need this Ref anymore so we can just return a normal div just like that now if I come up here and I just want to put in something that says console that log node so we can see that this is working and if we save this search for test and if I inspect our page you can see that that last book which is Scandinavian cooking is getting logged out to us so it's calling this last book element ref every single time we render that component now all we have left to do is actually set up our intersection observer in here so though we know when were on our last element so the first thing we can do is we can say if loading so we want to check if we are loading then we just want to return because if we're loading our information we don't want to trigger our infinite scrolling because otherwise it'll just constantly call the API while we're loading and we definitely don't want that so with that other way the next thing we need to do is we want to check to see if we have an observer so the way refs work is they have a variable property called current which is whatever the current iteration of that variable is so if we have an observer what we want to do is we want to disconnect that observer because we're going to reconnect it so we can save our observer current dot disconnect call that function this is going to disconnect our observer from the previous element so that way our new last element will be hooked up correct and we just make sure we check our observer because as you remember by default this is going to be null the very first time around the next thing we need to do is set our current observer so we can say observer current is going to be equal to a new intersection observer and this is going to take in a function and this function takes all the entries that are available so everything that it's watching is going to be in this entries array as soon as they become visible we're going to implement this function in just a little bit but we want to finish out our function here by saying if we have a node so for example if something is actually our last element we just want to make sure that our observer is observing it so we can get our current observer and we can now say that we want to observe our node just like that and just like all the other callbacks that you get with hooks we actually need to return a list of dependencies in our case our dependencies are going to be loading as well as has more these are our only two dependencies that we're going to be messing with and now inside of this function we can implement this so the first thing we want to check is if entries and we want to get our first entry because we're only ever observing one single node so if our note that we're observing we want to say if it's intersecting essentially that means it's on the page somewhere then we're just going to console that log visible so we can actually see if this is working and of course we're getting an error and that's just because this hook down here which is actually getting our loading information I need to just move this up so that it's above the code that's actually using that loading so we'll just put it all the way at the top here and now if we save this that error should go away perfect now we can type in test and you can see nothing's getting logged but as soon as we get to the very bottom of our page and that element becomes visible you'll see it gets logged out that it's visible which is exactly what we want and inside of this code we can actually add one to our page so we could just say set page number whoops set page number we want to get our previous page number and all we want to do is add one to that so we'll say previous page number plus one just like that and also the last thing we need to check inside of here is if we have more so the reason we're checking has more is if we're out of elements to query essentially our API has queried all the data we don't want to continually keep calling this API so this won't allow us to keep paginating forever because otherwise it would just paginate forever so now let's save this and see if this works if we type in test and we scroll all the way to the bottom of our page you can see we get the text loading and it allows us to scroll some more and we get loading again and if we search something that's a little bit more specific so that we can test to see if our has more works we can say the Lord of the Rings and now it's loading and as soon as that's done loading we can see that we can scroll all the way down it's loading scroll a little bit more loading keep going you can see we got loading again and hopefully we're getting close to the end here as you can see that's the very end the loading went away and it's not trying to keep querying our API it just completely stopped which is exactly what we want and that's all it takes to set up infinite scrolling with react if you enjoyed this video make sure to check out my other videos linked over here and subscribe to the channel for more videos like this one thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 131,074
Rating: 4.9358521 out of 5
Keywords: webdevsimplified, infinite scrolling, infinite scroll, infinite scrolling react, infinite scrolling js, infinite scroll react, infinite scroll js, infinite scroll javascript, infinite scrolling javascript, infinite scrolling with react, infinite scroll tutorial, infinite scroll react tutorial, react hooks project, react project, react tutorial, react pagination, intersection observer, intersection observer tutorial, intersection observer react, intersection observer api, react
Id: NZKUirTtxcg
Channel Id: undefined
Length: 25min 27sec (1527 seconds)
Published: Tue Oct 01 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.