Conditional Fetching - Redux-Toolkit Query (RTK Query)
Tags: redux, tutorial, beginners, webdev
Published: 2022-11-16 11:37:24

**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.

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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

```javascript
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:
{% youtube U-GtBj82JUw %}

Thanks for reading! ❤