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 in React

Redux with Redux Toolkit is the standard solution for complex global state in React applications — when Context API becomes too verbose or performance-intensive, Redux provides predictable state updates with excellent DevTools support. As the creator of CoreUI with 25 years of front-end development experience, I use Redux Toolkit (RTK) in large-scale React dashboards where multiple features share state and async data fetching needs centralized management. Redux Toolkit eliminates the boilerplate of classic Redux — no separate action creators, no switch statements, just slices with immer-powered reducers. Start with the simplest state management that works; reach for Redux when you have genuinely complex cross-component state.

Install Redux Toolkit and React Redux.

npm install @reduxjs/toolkit react-redux

Create a slice with actions and reducer.

// store/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'

export const fetchUsers = createAsyncThunk(
  'users/fetchAll',
  async (_, { rejectWithValue }) => {
    try {
      const res = await fetch('/api/users')
      if (!res.ok) throw new Error('Failed to fetch')
      return await res.json()
    } catch (err) {
      return rejectWithValue(err.message)
    }
  }
)

const usersSlice = createSlice({
  name: 'users',
  initialState: {
    list: [],
    loading: false,
    error: null
  },
  reducers: {
    addUser(state, action) {
      state.list.push(action.payload) // Immer allows direct mutation
    },
    removeUser(state, action) {
      state.list = state.list.filter(u => u.id !== action.payload)
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUsers.pending, (state) => {
        state.loading = true
        state.error = null
      })
      .addCase(fetchUsers.fulfilled, (state, action) => {
        state.loading = false
        state.list = action.payload
      })
      .addCase(fetchUsers.rejected, (state, action) => {
        state.loading = false
        state.error = action.payload
      })
  }
})

export const { addUser, removeUser } = usersSlice.actions
export default usersSlice.reducer

createSlice generates action creators automatically from the reducer functions. Immer (built into RTK) allows writing mutations directly — state.list.push() — without spread operators. createAsyncThunk handles the pending/fulfilled/rejected lifecycle automatically.

Configure the Store

// store/index.js
import { configureStore } from '@reduxjs/toolkit'
import usersReducer from './userSlice'

export const store = configureStore({
  reducer: {
    users: usersReducer
  }
})
// main.jsx
import { Provider } from 'react-redux'
import { store } from './store'

ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider store={store}>
    <App />
  </Provider>
)

Using Redux in Components

// UserList.jsx
import { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { fetchUsers, removeUser } from './store/userSlice'

export function UserList() {
  const dispatch = useDispatch()
  const { list, loading, error } = useSelector(state => state.users)

  useEffect(() => {
    dispatch(fetchUsers())
  }, [dispatch])

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

  return (
    <ul>
      {list.map(user => (
        <li key={user.id}>
          {user.name}
          <button onClick={() => dispatch(removeUser(user.id))}>Remove</button>
        </li>
      ))}
    </ul>
  )
}

useSelector subscribes to the store and re-renders the component when the selected state changes. useDispatch provides the store’s dispatch function. Both hooks replace connect() from older Redux patterns.

Best Practice Note

This is the same Redux Toolkit setup used in CoreUI React templates for applications with complex global state. For simpler apps, Context API with useReducer avoids the Redux dependency entirely. Use Redux when you need: DevTools for state inspection and time-travel debugging, middleware for logging or analytics, or when more than 3-4 nested components share state. See how to use Redux Toolkit in React for advanced RTK Query patterns that handle data fetching with built-in caching.


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