This time we will make an image search engine with the help of Unsplash API and React Query, with which you will notice a big change in your applications, with so few lines of code, React Query will improve the performance of your application!
π¨ Note: This post requires you to know the basics of React with TypeScript (basic hooks).
Any kind of feedback is welcome, thanks and I hope you enjoy the article.π€
It will receive the event, in which we will have all the necessary to recover all the data of each input inside the form that in this case is only one input.
Now we are going to use the fromEntries function of the Object instance sending a new instance of FormData which in turn receives the target property of the event.
This will return us each one of the values inside our form. And which we can destructure.
Although it doesn't help us the autocompletion to destructure each value of the input
Well, we have already obtained the value of the input, now we are going to validate that if its length is 0, that it does nothing.
And if that condition is not met, then we will have our keyword to search for images.
By the way, also delete the form and put the focus on the input.
All good, but now the problem is that we have it all in the Form.tsx component and we need to share the query state to communicate what image we are going to look for.
So the best thing to do is to move this code, first to a custom hook.
Inside the folder src/hook we create a file index.tsx and add the following function:
exportconstuseFormQuery=()=>{}
We move the handleSubmit function inside the hook and also the state.
And we return the value of the state (query) and the function handleSubmit.
For the moment we are only going to make the shell of this component.
This component will receive the query (image to search) by props.
This is where the request to the API will be made and display the cards.
import{Card}from'./Card';interfaceIGridResults{query:string}exportconstGridResults=({query}:IGridResults)=>{return(<><pclassName='no-results'>
Results with: <b>{query}</b></p><divclassName='grid'>{/* TODO: map to data and show cards */}</div></>)}
Now let's use our GridResults.tsx in src/App.tsx.
We will display it conditionally, where if the value of the query state (the image to search for) has a length greater than 0, then the component is displayed and shows the results that match the search.
React Query makes it easy to fetch, cache and manage data. And that's what the React team recommends instead of doing a simple fetch request inside a useEffect.
Now let's go to the terminal to install these dependencies:
npm install @tanstack/react-query axios
After installing the dependencies, we need to wrap our app with the React query provider.
To do this, we go to the highest point of our app, which is the src/main.tsx file.
First we create the React Query client.
We wrap the App component with the QueryClientProvider and send it in the client prop our queryClient.
We will use a react-query hook that is the useQuery, which receives 3 parameters, but for the moment we will only use the first two.
The first parameter is the queryKey which is an array of values (arrays with values as simple as a string or complex as an object), it is used to identify the data that was stored in the cache. In this case we send an array of with the value of the query.
useQuery([query])
The second parameter is the queryFn, it is the function that makes the request and returns a promise already resolved with the data or an error.
For this we are going to create our function, in the src/utils folder we create the index.ts file and create a function.
This function is asynchronous and receives a query of type string and returns a promise of type ResponseAPI,
We build the URL, it is worth mentioning that we need an API Key to use this API. Just create an Unsplash account. Create an app and get the access key.
Then we do a try/catch in case something goes wrong.
Inside the try we make the request with the help of axios. We do a get and send the url, unstructure the data property and return it.
In the catch we will only throw an error sending the message.
Now if we are going to use our function getImages, we send it to the hook.
But, as this function receives a parameter, we need to send it in the following way: we create a new function that returns the getImages and we send the query that arrives to us by props
β Don't do it that way.
useQuery([query],getImages(query))
β Do it like this.
useQuery([query],()=>getImages(query))
And to have typing we are going to put that the data is of type ResponseAPI.
import{Card}from'./Card';interfaceIGridResults{query:string}exportconstGridResults=({query}:IGridResults)=>{const{data,isLoading,error,isError}=useQuery<ResponseAPI>(['images',query],()=>getImages(query))return(<><pclassName='no-results'>
Results with: <b>{query}</b></p><divclassName='grid'>{/* TODO: map to data and show cards */}</div></>)}
Now that we have the data, let's show a few components here.
1 - First a condition, to know if isLoading is true, we show the component Loading.tsx.
2 - Second, at the end of the loading, we evaluate if there is an error, and if there is, we show the error.
3 - Then we make a condition inside the p element where if there are no search results, we display one text or another.
4 - Finally, we go through the data to show the images.
And that's it, we could leave it like that and it would look very nice.
Showing the loading:
Showing search results:
But I would like to block the form while the loading is active.
For this the Form.tsx component must receive another prop which is isLoading and place it in the disable property values of both the input and the button.
In src/App.tsx we unstructure isLoading and handleSubmit of the hook. And isLoading we send it to the Form component and the function we send it to the GridResults component.
In the component GridResults.tsx we are going to receive the new prop that is handleLoading, we unstructure it, and inside the component we make a useEffect before the conditions, and inside the useEffect we execute handleLoading and we send the value of isLoading that gives us the hook useQuery and the useEffect will be executed every time that the value isLoading changes, for that reason we place it as dependency of the useEffect.
And ready, this way we will block the form when the request is being executed.
π§ Conclusion.
I hope you liked this post and that it helped you to understand a new approach to make requests with react-query! and grow your interest in this library that is very used and very useful, with which you notice incredible changes in the performance of your app. π€
If you know of any other different or better way to perform this application, please feel free to comment. π.
I invite you to check my portfolio in case you are interested in contacting me for a project!. Franklin Martinez Lucas
π΅ Don't forget to follow me also on twitter: @Frankomtz361
Franklin Martinez
@frankomtz361
Hi there! π
My name is Franklin Martinez.
I'm a Front-End developer and I specialize in JavaScript and React JS technologies. βοΈ I also like to publish β some articles.