
Redux interview questions for freshers test whether you can choose and explain a state model, not whether you memorized the phrase "single source of truth." Connect the UI problem to Redux's data flow: state lives in a store, the UI dispatches events, reducers calculate the next state, and components read only the data they need.
In 2026, answer Redux questions with Redux Toolkit as the default. Older tutorials show hand-written action types, createStore(), switch-heavy reducers, and lots of boilerplate. You should still understand those ideas, but modern Redux code normally uses configureStore(), createSlice(), React Redux hooks, and RTK Query or thunks for async work.
If you want hands-on practice, implement Redux Store and Redux Store II on GreatFrontEnd after reading this guide.
| Interview prompt | What the interviewer is checking | Common fresher mistake |
|---|---|---|
| "The navbar cart count updates from many pages. Where should that state live?" | Shared state and component communication | Putting everything in Redux without explaining why |
| "This reducer pushes into an array. Is that okay?" | Immutability and Redux Toolkit/Immer | Saying all mutation is always wrong, even inside createSlice() |
| "Why does this component re-render on every action?" | Selector return values and reference equality | Returning a new object from useSelector() every time |
| "Should a text input use Redux?" | Local vs global state | Dispatching on every keystroke by default |
| "How do you fetch products and cache them?" | Thunks vs RTK Query vs component fetch | Writing loading reducers for every endpoint without considering server-state tooling |
"A user can add items from product pages, search results, and recommendations. The navbar badge should update everywhere."
Redux is a reasonable choice because multiple distant components need the same state and the actions are meaningful product events: cart/itemAdded, cart/itemRemoved, cart/quantityChanged. The reducer owns the cart state; selectors expose selectCartCount and selectCartTotal.
Do not stop at "Redux avoids prop drilling." Name the shared state, the events, and the derived selectors the UI needs.
"A modal has a search box. Should the input value go into Redux?"
Usually no. The typed value is temporary UI state owned by one component. Keep it in React state unless another feature needs it, the value must survive navigation, or it is part of a shareable URL.
This scenario checks judgment. Redux skill includes knowing when not to use Redux.
"Where should product list loading, error, and cached data live?"
If the app already uses Redux Toolkit, RTK Query fits this case because product data is server state: it needs fetching, caching, invalidation, and refetching. A thunk still works for custom flows, but server state and client state are different problems.
"This selector returns
{ count, total }, and the component re-renders after unrelated actions. Why?"
Returning a new object creates a new reference on every store update. Split selectors, use a memoized selector, or use an equality function when appropriate.
const count = useSelector(selectCartCount);const total = useSelector(selectCartTotal);
The interviewer is checking whether you understand React Redux's render behavior, not only Redux vocabulary.
"A user likes a post. The UI updates immediately, but the API fails. What should happen?"
Dispatch an optimistic action, keep enough information to roll back, and handle the failure action by reverting or showing a retry state. For server-state flows, use the mutation lifecycle provided by the data library.
The product detail matters: a like can be retried or reverted; a payment cannot be treated casually.
Provider, useSelector, and useDispatch?Redux is a predictable state management library for JavaScript apps. It stores application state in a single store and updates that state by dispatching actions to reducers.
In React apps, Redux fits state that many components need, state that benefits from debugging history, or server/cache state managed through Redux Toolkit Query.
Add this detail: Do not pitch Redux as "global variables for React." Say it fits state transitions that need structure, traceability, and consistent reads across distant components.
Official reference: Getting Started with Redux.
Redux solves prop chains through many component layers, shared reads across distant components, and state transitions that need a traceable action history.
It is not needed for every piece of state. Input text, modal open state, hover state, and small component-only state belong in React local state.
Example: Cart, auth session metadata, feature flags, editor document state, and cross-page notification queues have a clearer Redux payoff than a single input's current value.
The core concepts are store, actions, and reducers.
The store holds state. Actions describe what happened. Reducers receive the previous state and an action, then return the next state.
The store is the object that holds the entire Redux state tree. It lets you read state with getState(), update state with dispatch(action), and subscribe to changes.
In modern Redux, create the store with Redux Toolkit's configureStore(), not the older createStore() API.
Official reference: Redux Store API.
An action is a plain object that describes something that happened in the app. It must have a type field and may include a payload.
{type: "cart/itemAdded",payload: { id: "p1", quantity: 1 }}
Good action names describe events, not setter operations. cart/itemAdded is clearer than SET_CART.
A reducer is a pure function that calculates the next state from the previous state and an action.
function counterReducer(state = { value: 0 }, action: { type: string }) {if (action.type === "counter/incremented") {return { value: state.value + 1 };}return state;}
Reducers should not fetch data, mutate external variables, read time randomly, or dispatch actions.
How to test this answer: A reducer should be easy to unit test with plain inputs and outputs. If the reducer needs the current time, random IDs, network data, or localStorage, that work belongs before the action is dispatched or in async/middleware logic.
Pure reducers make Redux predictable. Given the same previous state and action, the reducer should return the same next state.
This predictability enables debugging, replaying actions, testing reducers as simple functions, and understanding state changes from the Redux DevTools history.
dispatch() sends an action to the Redux store. The store runs the root reducer with the current state and the dispatched action, then stores the new state.
In React components, you normally dispatch action creators:
const dispatch = useDispatch();dispatch(cartItemAdded({ id: "p1" }));
Redux data flow goes in one direction:
This keeps state changes from happening in many unrelated places.
Redux Toolkit is the official recommended way to write Redux logic. It includes helpers like configureStore(), createSlice(), createAsyncThunk(), and RTK Query.
It reduces boilerplate, sets up store defaults, includes development checks for common mistakes, and lets reducers use draft mutation syntax through Immer.
Official reference: Redux Style Guide.
configureStore()?configureStore() creates a Redux store with sensible defaults. It combines reducers, adds middleware, enables Redux DevTools in development, and includes checks that catch accidental mutations and non-serializable values.
import { configureStore } from "@reduxjs/toolkit";export const store = configureStore({reducer: {cart: cartReducer,user: userReducer,},});
createSlice()?createSlice() creates a slice reducer, action creators, and action types from one feature-focused definition.
const counterSlice = createSlice({name: "counter",initialState: { value: 0 },reducers: {incremented(state) {state.value += 1;},},});
The code looks like mutation, but Redux Toolkit uses Immer to produce immutable updates safely.
Fresher trap: This does not mean "Redux allows mutation now" everywhere. The safe draft mutation applies inside Immer-powered reducers created by Redux Toolkit. Outside that boundary, keep immutable update rules in mind.
A slice is the Redux logic for one feature or domain, such as cart, auth, todos, or products. It contains initial state, reducers, generated actions, and selectors for that feature.
Feature-based slices keep related state, actions, and reducers in the same file instead of scattering one feature across action, reducer, and constant folders.
Redux Toolkit uses Immer. Immer gives your reducer a draft version of state. You write changes to the draft, and Immer produces the next immutable state behind the scenes.
This is why state.value += 1 is okay inside a createSlice() reducer but mutating state directly in a plain hand-written reducer is not okay.
Immutability means you do not change the existing state object. You return a new object or array for changed parts and reuse unchanged parts.
Redux relies on reference changes to know what changed. If you mutate the same object and return it, React Redux may not detect a change correctly.
React Redux is the official binding library that connects React components to a Redux store. It provides <Provider>, useSelector(), and useDispatch().
<Provider store={store}> makes the Redux store available to components. Hooks then read and update the store.
Official reference: React Redux hooks.
<Provider> do?<Provider> passes the Redux store through React context so any nested component can use React Redux hooks.
Without <Provider>, useSelector() and useDispatch() do not know which Redux store to use.
useSelector()?useSelector() reads a value from the Redux store. It accepts a selector function and re-renders the component when the selected value changes.
const cartCount = useSelector((state: RootState) => state.cart.items.length);
Return the smallest value the component needs. Returning a new object every time can cause unnecessary re-renders.
Bad pattern:
const cart = useSelector((state) => ({count: state.cart.items.length,total: state.cart.total,}));
This creates a new object on every store update. Prefer separate selectors or a memoized selector when returning derived objects.
useDispatch()?useDispatch() returns the store's dispatch function so a component can dispatch actions.
const dispatch = useDispatch();function onAddToCart(id: string) {dispatch(itemAdded({ id }));}
In TypeScript apps, many teams create a pre-typed useAppDispatch() hook based on the store's dispatch type.
Selectors are functions that read specific data from Redux state.
const selectCartItems = (state: RootState) => state.cart.items;
Selectors keep components from knowing the exact state shape. If the store shape changes, you update selectors rather than every component.
Memoized selectors cache derived results. Use them for filtered lists, totals, or expensive derived values from state.
Use memoization when the derived calculation is expensive or returns new arrays/objects that would otherwise cause unnecessary re-renders.
Reducers must stay pure, so async work happens outside reducers. Common options are thunks, createAsyncThunk(), RTK Query, or custom middleware.
For freshers, know the common flow: dispatch pending, perform the request, dispatch success or failure, and update state based on those actions.
How to choose: Use RTK Query for normal CRUD/server data. Use thunks for custom workflows that coordinate multiple actions, read current state, or mix API calls with client-owned state changes.
A thunk is a function that can contain async logic and dispatch actions later. Redux Toolkit includes thunk middleware by default.
export const fetchUser = (id: string) => async (dispatch: AppDispatch) => {dispatch(userRequested());const user = await api.getUser(id);dispatch(userReceived(user));};
Use thunks for app logic that needs dispatch, getState, or multiple actions around one async operation.
createAsyncThunk()?createAsyncThunk() is a Redux Toolkit helper for request-style async logic. It automatically creates pending, fulfilled, and rejected action types.
Reducers handle those cases in extraReducers, which keeps loading and error states predictable.
RTK Query is Redux Toolkit's data fetching and caching tool. It can generate hooks for queries and mutations, cache server responses, deduplicate requests, and invalidate data by tags.
Use RTK Query when the main problem is server data. Use slices and reducers when the main problem is client-owned application state.
Official reference: RTK Query overview.
Use React Context for dependency-style values such as theme, locale, or current user metadata. Use Redux when state changes frequently, many components need slices of it, debugging history matters, or update logic is complex.
Context alone does not provide reducers, middleware, DevTools history, normalized patterns, or built-in server-state caching.
Middleware runs between dispatching an action and the action reaching reducers. It can log actions, handle async functions, report analytics, or intercept certain actions.
Reducers should not have side effects. Middleware is one safe place for side-effect logic.
Redux DevTools show dispatched actions, state changes, and the current store state. They help debug why UI changed and what action caused it.
This is one reason Redux still appears in larger codebases: it gives teams a common timeline for state transitions.
Avoid putting non-serializable values such as DOM nodes, class instances, Promises, functions, and raw Date objects in Redux state. Also avoid storing tiny UI state that only one component uses.
Redux state should be serializable because DevTools, persistence, debugging, and predictable updates depend on plain data.
Reducers are easy to test because they are pure functions. Pass an initial state and an action, then assert the returned state.
For React components connected to Redux, render the component with a real test store when possible. For async data, mock the network boundary or use RTK Query testing patterns instead of testing internal implementation details.
Good reducer test shape:
expect(cartReducer({ items: [] }, itemAdded({ id: "p1" }))).toEqual({items: [{ id: "p1", quantity: 1 }],});
This tests the state transition rather than the implementation.
Redux is a tool for shared, traceable, complex state. A small form or one-page widget does not need it.
state.items.push(item) is only safe inside Redux Toolkit's Immer-powered reducers. In plain reducers, return a new array or object.
useSelector()If a selector returns a new object on every store update, the component can re-render on unrelated changes. Select the exact values needed or use memoized selectors.
Server state comes from the backend and needs fetching, caching, invalidation, and refetching. Client state is owned by the UI. RTK Query fits server state more directly than hand-writing loading reducers for every endpoint.
Build a mini cart state model:
cartSlice with itemAdded, itemRemoved, and quantityChanged.useSelector().itemAdded() from a product card.This small drill proves more Redux understanding than memorizing ten definitions.
For a fresher interview, a solid Redux answer has three parts: describe the data flow, state why reducers stay pure, and mention Redux Toolkit as the modern default.
100+ React interview questions and answers, prepared by senior engineers and ex-FAANG interviewers. Updated for 2026 with React 19 coverage including Actions, Server Components, the use hook, and the React Compiler.
Explore some of the most useful and impactful React ecosystem libraries.
Brush up on fundamental JavaScript skills with these essential interview questions and answers. Perfect for freshers preparing for junior developer roles.