Image by Vincent M.A. Janssen from Pexels
DESCRIPTION
Let's dive into a bit more complex examples of real-world scenarios. We'll fetch data when the user types in the search field or clicks on the button.
Introduction
In the previous How To Fetch Data In React From API guide, we covered data fetching topics in useEffect hook when the component mounts. I skipped the explanation of fetching data when the component updates (e.g. by typing in) or by clicking on something and triggering the event. I'll implement these 2 approaches and thoroughly explain them for you in this article.
Fetch data as we type
Please, take a look at below example application and refer to it as we'll recreate the exact same version step by step.
Prepare data fetching
We're recreating a similar code as in the previous article with some small but crucial differences.
searchQuery
will track what user types in our search field (we'll add it soon). useEffect
instead of empty dependencies []
has [searchQuery]
. It means, it'll run every time searchQuery
is updated. When searchQuery
is an empty string, we return the initial state of pokemon
data which is undefined
.As previously, we're using pokeAPI and when
searchQuery
is updated, we use browser fetch with async/await to get particular Pokemon data and save it in the state with setPokemon
function. Again, please notice response.json()
to get an actual JSON from the HTTP response. All of that happens inside of fetchData
async. function as useEffect
should return either nothing or cleanup function.Adding search field
For rapid prototyping, we're using Material UI components and its icon package to include a nice search icon on the right of our search field.
An important aspect is about Controlled Components in React as we added
handleChange
function and attached it to the TextField
component. Please, note value={searchQuery}
too. With all of it, we'll be able to track what user types and update it appropriately to trigger a new query to pokeAPI.Adding missing pieces
I've added more Material UI components to render our searched Pokemon in a card (name, image). To prevent unexpected errors (e.g. when pokemon doesn't exist and we won't receive data from the pokeAPI), there is a try...catch clause.
All gucci but wait a moment...
Are we hitting the API with each character typed in? 🙈
Yes, we're currently fetching data from the API on every character being typed in by the user. It'll hit the performance and if you're using APIs with limits (e.g. 100 or 1000 per hour), it'll quickly burn out.
To solve it, we'll use useDebouncedEffect (big thanks to the author of it), debounce technique is useful if you want to execute the function only after some cooling period (in our case, fetch) instead of doing it after every key pressed. Read Debounce vs Throttle to learn more about it.
I won't dive into the details of this hook as you can find an in-depth explanation in the above link. Create a file called
useDebouncedEffect.js
as we'll import the useDebouncedEffect
hook from it in our code below.We replaced
useEffect
hook with the useDebouncedEffect
. The first argument is still a function but the second one is a number, we provided 300
, the last argument is a list of dependencies as in useEffect
hook.The crucial part is about the number as we're not going to fetch the data unless there was 300 milliseconds cooling period (the user didn't type any letter for that time).
Wow, I understand know why there are so few resources available on the Web about this technique. It's quite difficult to explain. 😅 I hope it'll be useful to you at some point. Let's take a look at our finished application one more time for reference. Try to search for your favorite Pokemon, let's bring back the memories. (I think I love Charizard the most ❤️).
Fetch data on click
This part should be much easier 😀, I'll refactor the above code to achieve the end result.
I've used couple of additional Material UI components, including
Grid
and Button
to create the example application.useDebouncedEffect
was completely replaced by handlePokemonFetchClick
async. function. We're using almost the same code in it as previously, and it's triggered when the user clicks the button (please, notice onClick={handlePokemonFetchClick}
on the Button
component). Additionally, we disable the button when there is nothing in the search field. Let's look at our application.Summary
Perfect, you should be good now in all kinds of data fetching implementations, from standard one to the one when something needs to be typed in, ending with the button click. Good job!
There are more optimizations apart from debouncing we could add including caching or memoizing concepts. react-query handles them well and I'd recommend it instead of custom solutions. However, as you now know the buzzwords, nothing stops you from digging in. I won't promise to make another article about it but who knows... 👀
Big thanks for reading the article, you're awesome! 🙇♂️
You can also find me on:
Thanks for all the support. ❤️