Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to use Redux Toolkit in React

Redux Toolkit’s RTK Query is the most powerful data fetching and caching solution for Redux applications, automating loading states, error handling, and cache invalidation that you’d otherwise write by hand. As the creator of CoreUI with 25 years of front-end development experience, I use RTK Query in complex React dashboards where multiple components fetch the same data and need to stay synchronized without redundant API calls. Define your API once with createApi, and RTK Query generates typed hooks, manages caching, handles request deduplication, and automatically re-fetches stale data. This eliminates the need to write fetchUsers.pending, fetchUsers.fulfilled, and fetchUsers.rejected reducers for every endpoint.

Define your API with createApi.

// src/store/apiSlice.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'

export const api = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({
    baseUrl: '/api',
    prepareHeaders: (headers) => {
      const token = localStorage.getItem('token')
      if (token) headers.set('Authorization', `Bearer ${token}`)
      return headers
    }
  }),
  tagTypes: ['User', 'Post'],
  endpoints: (builder) => ({
    // Query endpoint
    getUsers: builder.query({
      query: (params = {}) => ({
        url: '/users',
        params
      }),
      providesTags: ['User']
    }),

    getUserById: builder.query({
      query: (id) => `/users/${id}`,
      providesTags: (result, error, id) => [{ type: 'User', id }]
    }),

    // Mutation endpoint
    createUser: builder.mutation({
      query: (body) => ({
        url: '/users',
        method: 'POST',
        body
      }),
      invalidatesTags: ['User'] // Refetch user list after creating
    }),

    updateUser: builder.mutation({
      query: ({ id, ...body }) => ({
        url: `/users/${id}`,
        method: 'PUT',
        body
      }),
      invalidatesTags: (result, error, { id }) => [{ type: 'User', id }]
    }),

    deleteUser: builder.mutation({
      query: (id) => ({ url: `/users/${id}`, method: 'DELETE' }),
      invalidatesTags: ['User']
    })
  })
})

export const {
  useGetUsersQuery,
  useGetUserByIdQuery,
  useCreateUserMutation,
  useUpdateUserMutation,
  useDeleteUserMutation
} = api

tagTypes and providesTags/invalidatesTags form the cache invalidation system. When createUser succeeds, it invalidates the User tag, causing getUsers to automatically re-fetch.

Configure the Store

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit'
import { api } from './apiSlice'

export const store = configureStore({
  reducer: {
    [api.reducerPath]: api.reducer
  },
  middleware: (getDefault) => getDefault().concat(api.middleware)
})

Using RTK Query Hooks in Components

// UserList.jsx
import { useGetUsersQuery, useDeleteUserMutation } from './store/apiSlice'

export function UserList() {
  const { data: users, isLoading, error } = useGetUsersQuery()
  const [deleteUser, { isLoading: isDeleting }] = useDeleteUserMutation()

  if (isLoading) return <p>Loading...</p>
  if (error) return <p>Error: {error.message}</p>

  return (
    <ul>
      {users?.map(user => (
        <li key={user.id}>
          {user.name}
          <button
            onClick={() => deleteUser(user.id)}
            disabled={isDeleting}
          >
            Delete
          </button>
        </li>
      ))}
    </ul>
  )
}

useGetUsersQuery() returns { data, isLoading, isFetching, error, refetch }. The hook deduplicates requests — if multiple components call useGetUsersQuery() simultaneously, only one network request is made. After deleteUser succeeds, the User tag is invalidated and the list automatically re-fetches.

Best Practice Note

This is the recommended data fetching pattern for Redux-based CoreUI React applications. RTK Query eliminates the need for separate loading/error state in your slices for server data. Keep server state in RTK Query and client-only state in regular slices. For non-Redux applications, React Query (TanStack Query) provides the same caching pattern without requiring Redux. See how to use Redux in React for the foundational Redux Toolkit setup.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team