Skip to content

Redux Basics for React Interviews

Redux is a predictable state management library used to manage global application state. It stores the entire application state in a single store and updates state through dispatched actions.

  • Centralized state management
  • Predictable state updates
  • Easier debugging
  • Time-travel debugging
  • Better state sharing between components

Redux solves:

  • Prop drilling
  • Managing complex shared state
  • Synchronizing state across multiple components
  • Maintaining predictable state changes

Example:

Instead of passing user information through multiple component levels, Redux stores it globally.

The entire application state is stored in one Store.

State cannot be modified directly. Changes happen through Actions.

Reducers update the state.

(state, action) => newState

Stores application state.

const store = configureStore({
reducer: rootReducer
});

Describes what happened.

{
type: "ADD_TODO",
payload: todo
}

Updates state based on action.

function todoReducer(state = [], action) {
switch (action.type) {
case "ADD_TODO":
return [...state, action.payload];
default:
return state;
}
}

Sends an action to the reducer.

dispatch(addTodo(todo));
flowchart TD
    A[Component] --> B[Dispatch Action]
    B --> C[Reducer]
    C --> D[Store Updated]
    D --> E[UI Re-renders]
  1. User performs an action.
  2. Component dispatches an action.
  3. Action reaches the reducer.
  4. Reducer creates a new state.
  5. Store updates its state.
  6. UI re-renders.

The Store holds the entire Redux state tree.

const store = configureStore({
reducer: rootReducer
});

Only one store is generally recommended.

Functions that return actions.

const increment = () => ({
type: "INCREMENT"
});

Usage:

dispatch(increment());

Reducers are pure functions that take the current state and an action and return a new state.

function counterReducer(state = 0, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
default:
return state;
}
}

Reducers:

  • Don’t modify existing state
  • Don’t call APIs
  • Don’t have side effects
  • Return the same output for the same input

Bad:

state.count++;

Good:

return {
...state,
count: state.count + 1
};

State should never be modified directly.

Wrong:

state.user.name = "John";

Correct:

return {
...state,
user: {
...state.user,
name: "John"
}
};

Redux Toolkit is the official recommended way to write Redux.

  • Less boilerplate
  • Built-in Immer support
  • Built-in thunk middleware
  • Easier configuration
const counterSlice = createSlice({
name: "counter",
initialState: { value: 0 },
reducers: {
increment: (state) => {
state.value++;
}
}
});
Traditional Redux Redux Toolkit
More boilerplate Less code
Manual store setup configureStore
Manual action types createSlice
Manual immutable updates Immer support
Complex Simple

Generates:

  • Reducer
  • Actions
  • Action types
const userSlice = createSlice({
name: "user",
initialState: {},
reducers: {
setUser(state, action) {
return action.payload;
}
}
});
const store = configureStore({
reducer: {
user: userReducer,
product: productReducer
}
});

Reads data from the Redux store.

const count = useSelector(
state => state.counter.value
);

Dispatches actions.

const dispatch = useDispatch();
dispatch(increment());
useState Redux
Local state Global state
Component-specific Shared across app
Simple Complex state management
No middleware Middleware support

Middleware sits between dispatch and the reducer.

flowchart LR
    A[Dispatch] --> B[Middleware]
    B --> C[Reducer]

Used for:

  • API calls
  • Logging
  • Authentication
  • Error handling

Examples:

  • Redux Thunk
  • Redux Saga
export const fetchUsers = () => {
return async (dispatch) => {
const res = await fetch("/users");
dispatch(setUsers(await res.json()));
};
};

Reducers should not perform API calls because they must remain pure, synchronous, and side-effect free.

Avoid Redux when:

  • The application is small.
  • There is very little shared state.
  • React Context is sufficient.

Use Context API for themes, language, or simple authentication state. Use Redux for complex business state. See the React Context API Interview Guide for the full Context API vs Redux comparison.

  • Normalized state
  • Memoized selectors
  • Selective re-renders via useSelector
  • Immutable updates
const api = createApi({
baseQuery: fetchBaseQuery({
baseUrl: "/api"
}),
endpoints: (builder) => ({
getUsers: builder.query({
query: () => "/users"
})
})
});

Benefits:

  • Caching
  • Refetching
  • Loading states
  • Error handling
Redux Zustand
Enterprise scale Lightweight
More boilerplate Minimal code
Rich middleware ecosystem Simpler
Best for large apps Best for small/medium apps

Redux Toolkit is typically preferred for enterprise applications with complex state management and debugging requirements.

Can Redux work without React?

Yes. Redux is framework-independent.

Can we have multiple stores?

Yes, but a single store is the recommended architecture.

What is the single source of truth?

The Redux Store.

Which hook reads state from Redux?

useSelector().

Which hook dispatches actions?

useDispatch().

Which Redux approach is recommended today?

Redux Toolkit (RTK).

  • Redux centralizes application state into a predictable single store.
  • State updates occur by dispatching actions that are handled by pure reducers.
  • Redux Toolkit is the recommended modern approach because it significantly reduces boilerplate.
  • Middleware such as Redux Thunk enables asynchronous logic while keeping reducers pure.
  • Use Redux for complex shared state, while React Context is often sufficient for simpler global state.