Fetching & Mutating Data with React-Query
SREY
Posted on September 20, 2023
Hello again, you might found me lame, messing things around but React Query would never be !
How can be fetching done in React Query ?
if you ever thought the above question lets deep dive than !
If you are inside the react.js community , you might have heard useQuery hook or might be if you read my last part of this series you might have knew it ; Does it ring a bell if not don't worry we will see what useQuery hook is !
useQuery
is a hook inside the react-query which manages different things for eg (inital Data fetching , loading states , refetching etc) this all stuff that too asynchronously in background !
const getuser = () => {
return axios.get("/api/v1/me");
}
const {
data: response,
isLoading,
isError,
} = useQuery(["fetch-s-history"], () => getUser());
}
Here in the above piece of code if we see the useQuery hook expects a queryKey which indeed is an array and a query function that returns the API response as promise untill you do it asynchronously, Moreover it has many more parameters that we can add like enabled (which is of great use though) wait we will explore together I swear!
Hence the useQuery Hook returns the data in our case response as we gave it an alias hence the response can be used across the code-base if we made a custom hook for it and return the same thing without destructing any of below
{data , isLoading , isError}
Does key unleash some power ?
Yes it does the queryKey helps in caching the data independently, when any dependency inside the query changes, the refetch of the query occurs on the basis of staleTime , so you might be wondering what exactly is a dependency, if you know React that I guess you do you may know the working of
useEffect()
hook it takes some dependency inside the dependency array to re render the component if you don't add any by default the useEffect will run your custom logic written inside the hook and it will get called after performing all the DOM updates.
Let's see exactly what I said
type todoState = "done" | "pending" | "all"
type todo = {
id : number ;
currentState : todoState;
}
type todoProps = Array<todo>
const queryClient = new QueryClient();
const fetchTodos = async (state: todoState): Promise<todoProps> => {
return await axios.get(`api/get/todo/${state}`)
}
export const useFetchQueryTodos = (state : todoState) => {
useQuery({
queryKey: ['todos', state],
queryFn: () => fetchTodos(state),
initialData: () => {
const allTodos = queryClient.getQueryData<todoProps>(['todos', 'all'])
const filteredData =
allTodos?.filter((todo) => todo.currentState === state) || []
return filteredData.length > 0 ? filteredData : undefined;
)}
}
So if we see above, the piece of code changes when the user changes the currentState of the todo like from done to pending or pending to done , hence the data will be fetched and then we can filter the data on that basis if we need done we have a state matching it with the todo.currentState and if its pending state it follows the same set of instruction.
Let's talk about enabled as we left it while we were discussing the querykey
so What can we do is we can make a query dependable for example if a query1 gets depended on a id which I get from a different query2 so we can make our query1 dependable on query2 here it is how :
const {data : products} = useQuery({
queryKey: ['products'],
queryFn: getProductData,
})
const productId = product?.id
const {data : productDetail ,
isLoading : isproductDetailLoading } = useQuery({
queryKey :["product-detail],
queryFn : () => getProductFn(productId),
enabled : !!productId
})
So here in above example we can see we fetched the productDetail using the useQuery hook but we allowed the query on when there is a enabled state is set to true (cause enabled take a boolean value) hence if you want to disable a query from running automatically we go and make enabled parameter to false
so does it mean we only make a query disable using enabled parameter that`s not the case , we can also make it enable later at anytime as you can see in my above example where I took the productId and allow a query when the value of enabled is turned to true ,
But what if enabled is false ?
Lets get to that case
if query have a cache , then the query initialized with the status of success
the query will not automatically fetch on mount and also it will not refetch automatically in the background
The query will ignore query client invalidateQueries and refetchQueries calls that would normally result in the query refetching.
Also if it does not have cache data the query status will be set to loading
UseMutation hook ...
(the state keeping track for mutation 😌)
So what is mutation ;
Mutation for example when we login using our email and password the server returns us a token as a response hence it is just a classic example of managing a server state with useMutation hook , For a better definition remember Dominik?
(the guy who saved me from falling inside a trap) He got a great definition for this hook
As the name indicates, useMutation also has some sort of side-effect. Since we are in the context of managing server state with React Query, mutations describe a function that performs such a side effect on the server. Creating a todo in your database would be a mutation. Logging in a user is also a classic mutation, because it performs the side effect of creating a token for the user.
-- Dominik's blog
Let's dive with an example on useMutation Hook
(bear with me my code blocks has some issue i promise the white screen will never be back again )
you heard me saying sideEffect, So what is a sideEffect ?
In react we say a side-effect is when we perform something outside the scope of react , so in react-query we say this in the context of managing state server side hence when we create something like making a signup API hit and making a mutation on the database ; making a database entry for that particular user.
So there are many similarities between useQuery and useMutation, but as we saw in react-query run queries automatically and also smartly runs in background for some data updates to keep client and server in sync , but what if the mutation just follow the same way , if i wanted to add a list of users on my application , and each time if it run the mutate query every time my browser window focus so we dont make it run immediately but we can make them run on some action for example i create a add button beside the user i want to add and invoke a function but wait which function might be {mutate : mutatioFn}
so in a way we can say mutateFn with the help of useMutation() hook that we wrote will only invoke when we want to mutate something like updation of profile or addition of new password etc.
One more thing is that we can use useQuery (as it have a state shared) hence we can make a query run in different component and return the same cache data but it wont with the useMutation hook
Thats all from my side, but want to have a good look in it untill I publish further have a look on Dominik's blog and React-Query docs as well up-till then have a look at cleaning the code we usually used to mess with React-Query
Thanks for the amazing response on the first two part, Good Bye Fellas.
Posted on September 20, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.