React Query with Redux: Everything to Know

Photo of author

Two important technologies, React Query and Redux, play vital roles in ensuring that an application performs well and is easy to maintain in the ever-changing React development ecosystem. This article delves into react query with redux as well as their unique functionalities, stressing why they are important in achieving simplified data processing and scalable codebases.

React Query is a declarative framework for making remote data fetching, caching, and server-side data synchronization much easier. On the other hand, Redux is a sophisticated state management package that centralizes the application state using unidirectional data flow, guaranteeing predictability and traceability.

In this introduction to React Query and Redux, we’ll have a comprehensive but concise sweep of each library’s fundamentals, merits, and demerits and how the two can be intermarried to get the best of both worlds.

Table of Contents

React Query with Redux: Fundamentals

React Query is a Javascript library primarily for caching, managing, and updating local and remote data in React apps. It presents a pool of utilities that streamline the processes of caching, state management, and data fetching.

Fundamentals of React Query

Let’s take a deep dive into the fundamentals of React Query, channeling our focus on caching, data fetching, and asynchronous actions.

Data Fetching with ‘use query’

React Query utilizes the ‘useQuery’ hook for data fetching. It captures the query key and a function responsible for data fetching.

Example:

(jsx)

import { useQuery } from ‘react-query’;

const { data, error, isLoading } = useQuery(‘myQueryKey’, fetchDataFunction);

Caching and Stale-WHile-Revalidating

React Query utilizes a stale-while-revalidate strategy and automatic data caching. Cached data is immediately used and re-fetch is activated in the background.

Example:

(jsx)

const { data } = useQuery(‘myQueryKey’, fetchDataFunction, {

staleTime: 60000, // Cache data for 60 seconds

refetchOnWindowFocus: false, // Disable automatic refetching on window focus

});

Invalidations and Manual Refetching

‘useQuery’ has a ‘refetch’ function which you can use to trigger a refetch manually.

Example:

(jsx)

const { data, refetch } = useQuery(‘myQueryKey’, fetchDataFunction);

const handleButtonClick = () => {

refetch();

};

See Also: Passing Functions As Props In React: Full Guide

Mutations for Data Modification

The function ‘useMutation’ is used for async actions that alter data on the server.

Eg.:

(jsx)

import { useMutation } from ‘react-query’;

const mutation = useMutation(updateDataFunction, {

onSuccess: () => {

queryClient.invalidateQueries(‘myQueryKey’); // Invalidate and refetch related queries

},

});

Automatic Caching

Automatic caching is a phenomenon whereby React Query automatically caches query results, narrowing down the need for manual caching tactics. Cache data is placed in memory, and the library cleverly manages background re-fetching and stale data.

Automatic Caching

Caching is essential in that it boosts application performance by avoiding unimportant network requests.

Intuitive API

React Query opens doors to hooks like ‘useMutation’ and ‘useQuery’. These are intuitive, plus simple API hooks used to fetch and update data.

This API tool is designed to be developer-friendly, easy to integrate with React components, and very easy to understand. As queries are defined declaratively, the library manages the hidden complexities of caching and data fetching.

Understanding Redux

Redux is a state management library that is commonly coupled with React applications. Other Javascript frameworks can integrate with Redux for its centralized and predictable manner of operation.

Understanding Redux

Store

A store is an object that houses the whole state of your application. It is a centralized single unit with the duty to maintain the state tree. It’s role extends further to allow or render permission to other components, giving them access and the ability to update the tree.

Actions

These are plain Javascript objects that stand as event representatives in the application. Actions should have a ‘type’ property that outlines, defines, and depicts the type of action being performed. Action creators are the functions responsible for creating activities.

Reducers

These functions dictate how the application’s state changes due to an action performed. Reducers take the current state and the action as inputs or arguments, then return the required new state. Eventually, the reducer functions are combined into a root reducer to define the comprehensive state of the application.

Dispatch

This Redux Store technique is employed to dispatch actions and activate state changes. Action dispatching enables components to interact with the store.

(javascript)

store.dispatch(increment());

Selectors

Selectors are functions designed for specific data extraction from the state and facilitate decomposing the state’s structure into constituent parts. This makes it easier to access relevant data.

(javascript)

const getCounter = (state) => state.counter;

Middleware

Middleware makes it possible to interact with actions before they reach reducers. The tasks middleware typically performs include side effect handling, logging, and asynchronous actions.

(javascript)

import { applyMiddleware, createStore } from ‘redux’;

import thunk from ‘redux-thunk’;

const store = createStore(rootReducer, applyMiddleware(thunk));

Comparing React Query and Redux

React Query and Redux are popular libraries for handling states in React applications, but their functions and use cases differ. Here is a comparison of React Query with Redux based on essential factors.

Comparing React Query and Redux

Data Fetching

React Query:

Offers a declarative method for obtaining data through the ‘useQuery’ hook. Based on the state of the data, it handles caching, background refetching, and state updates.

Redux:

Usually, it needs middleware to handle asynchronous tasks like data fetching (e.g., Redux Thunk). Developers must explicitly manage the state transition, and caching needs to be implemented separately.

State Management

React Query:

Mostly concerned with controlling the status of distant data. A query cache holds the data, and the library offers hooks to communicate with it.

Redux:

Intended for centrally controlling the state of an application as a whole. Reducers handle every state transition, and the store gives the application a single source of truth.

Changes and Adverse Reactions

React Query:

Offers a Mutation hook to manage changes in data. Allows for the automatic re-fetching of linked queries following a mutation and supports optimistic updates.

Redux:

Needs middleware (like Redux Thunk) to manage asynchronous operations, such as changing data. Developers must manage adverse effects.

Ease of Use

React Query:

It has an easy-to-use API to manage remote states and work with asynchronous data. It makes complicated situations like optimistic updating, caching, and prefetching simple.

Redux:

Compared to React Query, boilerplate code and initial setup may be more involved—calls for writing middleware, reducers, and action creators for asynchronous actions.

Community and Ecosystem

Community and Ecosystem

React Query:

Quickly becoming popular, emphasizing cutting-edge React development techniques. A vibrant community with extensive documentation.

Redux:

Well-known and extensively used within the React community. A vast ecosystem featuring a range of extensions, middleware, and development tools.

Pros and Cons of React Query and Redux

React Query

Merits

Declarative Data Fetching:

React Query streamlines the process of fetching data by offering a declarative API via hooks like ‘useQuery’,

Automatic Caching:

The library reduces the need for human state management and boosts efficiency by handling caching automatically,

Optimistic Updates:

This feature lets you update the user interface (UI) optimistically before the server verifies the data.

Query Invalidation:

This feature ensures that data is always current by allowing users to invalidate manually and prefetch queries.

Integration With React Suspense:

Works well with React Suspense, enabling components to suspend while data is being fetched, thus offering a seamless user experience.

DevTool Support:

It provides a DevTools add-on for monitoring and troubleshooting queries while developing.

Pagination and Infinite Loading:

Large dataset handling is easier with built-in pagination and infinite loading support.

Drawbacks

Learning Curve:

While the fundamentals are simple, comprehending and utilizing advanced features may take time and investigation.

Focused on Data Fetching:

React Query’s primary goal is to manage remote data; you may require other tools for more comprehensive state management.

Redux

Merits

Centralized State

Redux offers a centralized store that makes managing the state easier by acting as a single source of truth for the whole program.

Predictable State Changes

Pure functions (reducers) handle state changes to ensure predictability and ease of debugging.

Middleware Support

Middleware, such as Redux Thunk, allows for the controlled handling of asynchronous operations and side effects.

Large Ecosystem

Redux offers flexibility for a wide range of use cases thanks to its enormous ecosystem, which includes many middleware options, development tools, and extensions.

Time-Travel Debugging

Redux DevTools’ time travel debugging feature enables you to examine and replay state changes over time.

Community and Resources

Redux is an established library with a sizable and vibrant community offering many tutorials and documentation.

Drawbacks

Boilerplate Code

When implementing Redux, boilerplate code is frequently written for action creators, actions, reducers, and connecting components.

Complexity for Simple Scenarios

Redux may add needless complexity to small-to-medium-sized applications compared to more straightforward state management solutions.

Learning Curve

It may take some time and effort for beginners to understand the fundamentals of Redux. And it is recommended to get fluent with the basics before moving on to advanced concepts like Redux Selectors.

Asynchronous Curve

Although middleware can handle asynchronous actions, it may become challenging to manage asynchronous flows.

Real World Integration: Migrating Redux to React Query

Redux optimistic updates entail updating the user interface before the server confirms the outcome of a dispatched action (like a network request). The steps involved in moving from a Redux setup to an optimistic update strategy with React Query are as follows:

Real World Integration: Migrating Redux to React Query

Redux Setup With Optimistic Updates (Before Migration)

Considering you have a standard Redux configuration consisting of reducers, actions, and middleware for async actions

Action Creators:

(javascript)

// actions.js

export const updateData = (data) => ({

type: ‘UPDATE_DATA’,

payload: data,

});

Reducer

(javascript)

// reducer.js

const initialState = {

data: null,

loading: false,

};

const reducer = (state = initialState, action) => {

switch (action.type) {

case ‘UPDATE_DATA’:

return {

…state,

data: action.payload,

};

default:

return state;

}

};

 

export default reducer;

Middleware (eg., Thunk)

(javascript)

// middleware.js

export const updateDataAsync = (data) => {

return (dispatch) => {

dispatch({ type: ‘UPDATE_DATA’, payload: data });

// Simulate a network request

setTimeout(() => {

// Dispatch the result from the server

dispatch({ type: ‘UPDATE_DATA_SUCCESS’, payload: data });

}, 1000);

};

};

Migration Steps to React Query

Install React Query

(bash)

npm install react-query react-query/devtools

Update Components

(javascript)

// MyComponent.js

import React from ‘react’;

import { useMutation, useQueryClient } from ‘react-query’;

const MyComponent = () => {

const queryClient = useQueryClient();

const mutation = useMutation(

(newData) => {

// Simulate a network request

return new Promise((resolve) => {

setTimeout(() => {

resolve(newData);

}, 1000);

});

},

{

onSuccess: (newData) => {

// Optimistically update the UI

queryClient.setQueryData(‘myQueryKey’, newData);

},

}

);

 

const handleButtonClick = () => {

const newData = /* get new data */;

mutation.mutate(newData);

};

return (

<div>

<button onClick={handleButtonClick}>Update Data</button>

</div>

);

};

export default MyComponent;

Remove Redux Actions and Middleware

(javascript)

// actions.js

// Remove the updateData action creator

// middleware.js

// Remove the updateDataAsync middleware

Remove Redux Reducer

(javascript)

// reducer.js

// Remove the reducer file or remove the part related to UPDATE_DATA

Remove Redux Store and Provider Setup

(javascript)

// index.js

// Remove the Redux store setup and Provider component

Remove Redux Imports in Components

Eliminate any last Redux imports from your components.

Install and Integrate React Query DevTools (Optional)

(bash)

npm install react-query/devtools

Incorporate React Query DevTools to track and troubleshoot queries while they are being developed.

(javascript)

// react-query-config.js

import { ReactQueryDevtools } from ‘react-query/devtools’;

// … (your existing React Query setup)

export const ReactQueryProvider = ({ children }) => (

<QueryClientProvider client={queryClient}>

{children}

<ReactQueryDevtools />

</QueryClientProvider>

);

Converting Redux Store and Saga to React Query

Changing from a more conventional state management strategy to React Quary’s declarative API for data fetching, caching and mutations is necessary when converting a Redux store and Saga setup. Here’s a detailed how-to:

Install React Query:

Install the DevTools and the React Query library

Create a React Query Provider

To wrap your application, set up a QueryClient and QueryClientProvider. This will be the Redux Provider’s replacement.

Determining Redux Actions and Sagas

Determine which actions and sagas in your Redux setup are responsible for retrieving, updating, and managing side effects.

Replace Redux Actions with React Query Hooks

To handle data fetching and mutations, replace Redux actions with React Query Hooks (useQuery, useMutations, etc.).

Convert Redux Sagas to React Query Mutations

Move the logic from Redux Sagas to React Query Mutations to handle data mutations.

Remove Redux Store Setup and Reducers

Eliminate any related Redux Store and reducer setup.

Refactor Components

Reorganize components to connect to the Redux store via React Query hooks instead.

Optimistic Updates

Use React Query mutations on the Success callback to implement optimistic updates.

Test and Optimize

Ensure data fetching, catching optimistic updates, and mutations function as intended by thoroughly testing your application.

Code should be optimized using the new React Query-based configuration.

RTX Query: Bridging React Query with Redux

Redux toolkit is the official set of tools for creating Redux applications. The provision of a collection of utilities to minimize boilerplate code is intended to improve the development of Redux applications.

RTK Query is one of the Redux Toolkit libraries for data fetching and state management. Its goal is to make managing the associated states in a Redux application and submitting API requests easier.

Global State Management

RTK Query uses Redux for global state management by default because it is a component of the Redux Toolkit. It easily interfaces with the current Redux Store, giving you a single location to manage global and API-related states.

Global State Management

Shared Redux Store

You can use the same Redux Store for RTK and React Query. Depending on your needs and preferences, you can use RTK Query for some parts of data fetching and React Query for others with this integration.

Setting up and Configuring RTK Query in React Applications

Now let’s review the basic procedures for configuring RTK Query in a React application.

Install Required Packages

Installing the required packages should come first. You should install both RTK Query and Redux Toolkit since they are related.

(bash)

npm install @reduxjs/toolkit react-redux

Configure Redux Toolkit and RTK Query

Using the configStore function from @reduxjs/toolkit, create a redux store. This function accepts an object with properties that are reducers. Incorporate the @reduxjs/toolkit/query/react api reducer.

(javascript)

import { configureStore } from ‘@reduxjs/toolkit’;

import { api } from ‘./api’; // Define your API slices in the api file

const store = configureStore({

reducer: {

[api.reducerPath]: api.reducer,

},

middleware: (getDefaultMiddleware) =>

getDefaultMiddleware().concat(api.middleware),

});

export default store;

Create API Slice

Utilize createSlice from @reduxjs/toolkit to define your API slices. RTK Query will automatically generate the required reducers and actions using these slices for various API components.

Create API Slice

(javascript)

// api.js

import { createApi, fetchBaseQuery } from ‘@reduxjs/toolkit/query/react’;

export const api = createApi({

reducerPath: ‘api’,

baseQuery: fetchBaseQuery({ baseUrl: ‘/api’ }), // Replace with your API base URL

endpoints: (builder) => ({

// Define your API endpoints here

getUsers: builder.query({

query: () => ‘users’,

}),

// Other endpoints…

}),

});

export const { useGetUsersQuery } = api;

Create React Query Provider

Build a React Query Provider to encapsulate your whole application for simple debugging. Include the ReactQueryDevtools and QueryClientProvider.

Create React Query Provider

(javascript)

// react-query-config.js

import { QueryClient, QueryClientProvider } from ‘react-query’;

import { ReactQueryDevtools } from ‘react-query/devtools’;

const queryClient = new QueryClient();

export const ReactQueryProvider = ({ children }) => (

<QueryClientProvider client={queryClient}>

{children}

<ReactQueryDevtools />

</QueryClientProvider>

);

Wrap Your App With Providers

Use the React Query Redux store providers throughout your entire application

(javascript)

// index.js

import React from ‘react’;

import ReactDOM from ‘react-dom’;

import { Provider } from ‘react-redux’;

import { ReactQueryProvider } from ‘./react-query-config’;

import store from ‘./store’;

ReactDOM.render(

<React.StrictMode>

<Provider store={store}>

<ReactQueryProvider>

<App />

</ReactQueryProvider>

</Provider>

</React.StrictMode>,

document.getElementById(‘root’)

Advanced Implementation: Authentication and API Integration

Redux offers a centralized store for managing application state, while React Query is especially effective at handling data fetching and caching.

Here are some things to consider when utilizing Redux and React Query to combine authentication and API calls, including addressing how to efficiently update the state when props change in React, which is crucial for the seamless integration of these technologies.

Authentication

React Query For Authentication API Calls

For handling authentication API calls, use React Query. Login/logout processes can benefit from the useMutation hook.

Token Management With Redux

Utilize the Redux store to manage authentication tokens (like JWT). Dispatched actions to the token in the Redux state after successful authentication.

Redux For Authentication State

To handle the authentication state, employ Redux. Define redux action and reducers to manage authentication-related state changes, like login, logout, and token expiration.

Global Authentication State

Maintain global access to the Redux store’s authentication state. This enables various components within the application to respond to modifications in the authentication status.

React Query Devtools

During development, use the React DevTools to examine and troubleshoot the status of queries and mutations related to authentication.

API Integration

React Query For Data Fetching

Make use of React Query to retrieve data from your API. The useQuery hook makes refetching, caching, and data fetching easier.

API Integration

Redux For Global Application State

Use Redux to handle the state of your global application. Redux can manage a state that needs sharing between components or states unrelated to APIs, while react query handles state related to APIs.

Integrate React Query With Redux

Use the react-query/redux package to integrate React Query with the Redux store. This package contains utilities for sending React Query actions into the Redux store.

Middleware For API Requests

Make sure Redux Thunk or any other middleware you use for API requests works well with React Query. Keep your hands off React Query’s internal logic is meant to handle its query lifecycle.

Redux DevTools For API Actions

Utilize the Redux Devtools Extension to track and troubleshoot Redux actions connected to API requests to monitor the progression of events during async operations. This is especially helpful.

User Interface Integration and Middleware Components

Middleware Component for User Authentication

Create Middleware Function

Establish a middleware function that will intercept commands sent to the Redux store.

Check Authentication Actions

In the middleware, determine whether the intercepted action had anything to do with user authentication. This can apply to any action about authentication, including login, logout, and token f=refresh.

Access Redux Store State

To obtain data about user authentication, including tokens, user details, and authentication status, one can retrieve the present state of the Redux store.

Handle Authentication Logic

Using the intercepted actions as a basis, implement the logic for user authentication. This could entail launching more processes, contacting APIs, or updating the Redux store with the user’s current authentication state.

See Also: Mastering Redux-Saga Typescript: Full Guide

React Query Integration

Dispatch Actions for React Query

Use the middleware’s dispatch actions to communicate with React Query. For instance, based on changes related to authentication, you may wish to update the React Query cache, initiate refetches, or INvalidate particular queries.

Access React Query Hooks

Access React Query hooks directly within the middleware to initiate queries or mutations about authentication.

Handle API Request and Tokens

Include Tokens in API Requests

Adjust API requests inside the middleware to include the required authentication tokens in the headers if your authentication uses tokens (such as JTW).

Token Refresh

Put the middleware’s token refresh logic into action. Dispatch actions to refresh tokens and update the Redux store with the refreshed tokens when they expire.

See Also: ReactJS – prevState in the new useState React hook?

Error Handling

Handle Authentication Errors

When performing tasks related to authentication, implement error handling. To display error messages in the user interface, dispatch actions to update the Redux store with error information.

Dispatch Additional Actions

Dispatch Additional Actions

Send out further actions as necessary based on the flow of authentication. For Instance, send out commands to reroute the user following a successful login or to clear a specific state following a logout.

Integrate With the Redux Store

Connect Middleware To Redux

When setting up the store, integrate the middleware with the Redux store. The authentication middleware can be included by using Redux’s applyMiddleware function.

(javascript)

// Example store setup with middleware

import { createStore, applyMiddleware } from ‘redux’;

import rootReducer from ‘./reducers’;

import authenticationMiddleware from ‘./middleware/authenticationMiddleware’;

const store = createStore(

rootReducer,

applyMiddleware(authenticationMiddleware)

);

export default store;

See Also: Introduction To Redux Toolkit Testing 

FAQs

What is the difference between Redux Toolkit and RTK query?

Redux Toolkit is a package to streamline Redux-related operations such as action creation, state management, and reducer logic. RTX Query is a library that improves remote data management in a React application backed by Redux.

What is the RTK query used for?

Redux Toolkit Query is a library part of the Redux Toolkit used for data fetching and caching. It is made to operate smoothly with Redux and offers tools for managing remote data in a React application powered by Redux.

Why do we use Query in React?

As the name suggests, Query React is designed to request data remotely. It is used to attain optimistic updates, background data prefetching, declarative query configuration, automatic caching, and streamlined data fetching.

What is the difference between Axios and React queries?

Axios is a Javascript library created to make HTTP requests. Usually, its function is to communicate with APIs and perform data-fetching tasks from servers. On the other hand, Redux Query, though a library, is made specifically to manage remote and async data. It also allows easy operations like caching and data fetching to be performed.

Conclusion

In conclusion, there are differences between React Query and Redux, and utilizing one or the other will rely on your application’s complexity and particular needs. React Query with Redux combined is a popular and useful way to handle local and remote state management requirements.

We don’t always have to juxtapose React Query with Redux. They don’t always have to conflict with one another; in fact, they frequently work best together.

See Also: Understanding React Spread Props

Leave a Comment