Introduction: RTK Query is a powerful data fetching and caching tool. It is designed to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
Problem: Query hooks automatically begin fetching data as soon as the component is mounted. But, there are use cases where you may want to delay fetching data until some condition becomes true.
Solution:
- Using skip parameter in a hook
- Using Lazy Query hook
Requirements:
- Basic React Knowledge
- Basic Redux-Toolkit Knowledge
Project Setup
We'll start by installing redux-toolkit & react-redux library, so open a terminal and run the command below.
npm install @reduxjs/toolkit react-redux
Now, Create a folder named redux inside the src folder.
Inside this redux folder, We'll create our api.js & store.js files.
api.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// Generates react hooks for endpoints
export const api = createApi({
reducerPath: "api",
baseQuery: fetchBaseQuery({baseUrl: "https://jsonplaceholder.typicode.com/"}),
endpoints: (builder) => ({
getUsers: builder.query({
query: (user) => `users/${user}`
}),
})
});
// Export endpoints as hooks
export const { useGetUsersQuery } = api;
store.js
import { configureStore } from "@reduxjs/toolkit";
import { api } from "./api";
// Combines multiple states as root state
export const store = configureStore({
reducer: {
[api.reducerPath]: api.reducer,
},
// getDefaultMiddleware enables important feature like caching.
middleware: (getDefaultMiddleware) => {
return getDefaultMiddleware().concat(api.middleware)
}
});
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from "react-redux";
import { store } from "./redux/store";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
// Wrap root component with Provider
// Provider accepts store (root state) as prop
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
Solution 1: Using skip parameter
App.js
import { useEffect, useState } from "react";
import { useGetUsersQuery } from "./redux/api";
function App() {
const [userData, setUserData] = useState();
const [isUser, setIsUser] = useState(true);
// Pass skip parameter that accepts a boolean
const { data } = useGetUsersQuery(1, { skip: isUser });
useEffect(() => {
if(data) {
setUserData([data]);
}
console.log(data)
},[data])
return (
<div className="App">
{userData && userData.map(item => (
<div key={item.id}>
<p>{item.name}</p>
<p>{item.email}</p>
</div>
))}
// Triggers fetch as skip parameter is false
<button onClick={() => setIsUser(false)}>Fetch User</button>
</div>
);
}
export default App;
Solution 2: Using Lazy Query hook
For using a Lazy Query hook, we have to make a minor change to the exports inside the api.js file.
api.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
export const api = createApi({
reducerPath: "api",
baseQuery: fetchBaseQuery({baseUrl: "https://jsonplaceholder.typicode.com/"}),
endpoints: (builder) => ({
getUsers: builder.query({
query: (user) => `users/${user}`
}),
})
});
// Add Lazy after "use" to convert it into Lazy Query hook
export const { useLazyGetUsersQuery } = api;
App.js
import { useEffect, useState } from "react";
import { useLazyGetUsersQuery } from "./redux/api";
function App() {
const [userData, setUserData] = useState();
// Returns trigger function and results object
const [getUsers, results] = useLazyGetUsersQuery();
useEffect(() => {
if(results && results.data) {
setUserData([results.data]);
}
console.log(results)
},[results])
return (
<div className="App">
{userData && userData.map(item => (
<div key={item.id}>
<p>{item.name}</p>
<p>{item.email}</p>
</div>
))}
// Fetch data on button click by envoking trigger function
<button onClick={() => getUsers(1)}>Fetch User</button>
</div>
);
}
export default App;
Video Tutorial:
Thanks for reading! โค
Top comments (3)
Just curious, why you're creating a local state to store the data returned from the hook? You can access this data directly from both useQuery (with skip) and useLazyQuery
You can't mutate the result in the useQuery directly. Try using map function to mutate the data to different structure and it'll give an error (read only data).
maybe to have UI updating in response to data fetching ?