Normally this is how we fetch data from the backend.
import axios from "axios";
import { useEffect, useState } from "react";
interface Users {
id: number;
name: string;
}
const Users = () => {
const [users, setUsers] = useState<Users[]>([]);
const [error, setError] = useState("");
useEffect(() => {
axios
.get("https://jsonplaceholder.typicode.com/users")
.then((res) => setUsers(res.data))
.catch((err) => setError(err.message));
}, []);
if (error) return <div>{error}</div>;
return (
<div>
{users.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
};
export default Users;
we use useState it allows you to add state to functional components and we use useEffect to fetch data from the backend and store in our state variable.
But there are few problems in this code.
- No request cancellation
- No separation of concerns
- No retries
- No automatic refresh
- No caching
1.) No request cancellation: we are not cancelling the request if our component is unmounted.
2.) No separation of concerns: the query logic is leaked inside the component, we can't reuse it anywhere.
3.) No retries : we are not retrying failed request.
4.) No automatic refresh: If the data changes, while the users is on this page, they don't see the changes unless they refresh.
5.) No caching: if you want to know what is caching? Caching is the process of storing data in a place where it can be accessed more quickly and efficiently in the future.
We have lots of problem, that's why we use React-query.
React Query is a powerful library for managing data fetching and caching in React applications.
To install react query
On your terminal
npm i @tanstack/react-query
import React from "react";
import ReactDOM from "react-dom/client";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App.tsx";
// We use QueryClient for managing and caching remote data in react query.
// first you need to create a new instance of Query client.
const queryClient = new QueryClient();
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
);
To fetch data with query hook
we use query hook to fetch the data and give configuration object with two properties
1.) queryKey
2.) queryFn
queryKey -> queryKey is the unique identifier for query, it used for caching, we set this in array of one or more values.
queryFn -> This is the function we use to fetch the data from the backend, this function should return a promise that resolves data or throws an error.
In the body the function I have used axios to fetch the data from the backend.
const userQuery = useQuery({
queryKey: ["users"],
queryFn: axios.get("https://jsonplaceholder.typicode.com/users").then(res => res.data)
})
This userQuery has bunch of properties like data, error, isLoading and so on.
let us destructure the userQuery.
const {data, error, isLoading} = useQuery({
queryKey: ["users"],
queryFn: axios.get("https://jsonplaceholder.typicode.com/users").then(res => res.data)
})
So when calling the query hook, we need to specify the type of errors that might happen when fetching data
const {data, error, isLoading} = useQuery<User[], Error>({
queryKey: ["users"],
queryFn: axios.get("https://jsonplaceholder.typicode.com/users").then(res => res.data)
})
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { useEffect, useState } from "react";
interface Users {
id: number;
name: string;
}
const Users = () => {
const { data, error, isLoading } = useQuery<User[], Error>({
queryKey: ["users"],
queryFn: () =>
axios
.get<Users[]>("https://jsonplaceholder.typicode.com/users")
.then((res) => res.data),
});
if(isLoading) return <div>Loading....!</div>
if(error) return <div>{error.message}</div>
return (
<div>
{data?.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
};
export default Users;
But there is problem in this code, we don't have separation of concerns, our query is leaked.
so create a folder called hooks -> create a file called useUsers.ts
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
interface Users {
id: number;
name: string;
}
const useUsers = () =>
useQuery<Users[], Error>({
queryKey: ["users"],
queryFn: () =>
axios
.get<Users[]>("https://jsonplaceholder.typicode.com/users")
.then((res) => res.data),
});
export default useUsers;
import useUsers from "./hooks/useUsers";
const Users = () => {
const { data, error, isLoading } = useUsers();
if (isLoading) return <div>Loading.....!</div>;
if (error) return <div>{error.message}</div>;
return (
<div>
{data?.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</div>
);
};
export default Users;
Thank you!
Top comments (0)