🌍 ReactJS · subject
ReactJS State Management Syllabus
The State Management syllabus for ReactJS in full: 3 chapters and 9 topics, every one listed below, plus 50 State Management flashcards with answers.
State Management syllabus: all 3 chapters
Expand any chapter to see its topics and sub-topics.
-
useState Hook
3 topics- Initializing State
- Updating State
- Using Multiple State Variables
-
useReducer Hook
3 topics- When to Use useReducer
- Setting Up Reducer
- Dispatching Actions
-
Context API
3 topics- Creating Context
- Providing Context
- Consuming Context
ReactJS State Management flashcards — 50 questions with answers
In React function components, which Hook is used to add state?
The `useState` Hook. It lets a function component hold state that persists across re-renders.
What does `useState` return, and in what order?
It returns an array of exactly two elements: the current state value and a setter function to update it, e.g. `const [count, setCount] = useState(0)`.
What is the argument passed to `useState`?
The initial state value, used only on the first render. Example: `useState(0)` initializes state to `0`.
Why is array destructuring used with `useState`?
Because `useState` returns a two-element array `[value, setter]`; destructuring names them conveniently, e.g. `const [name, setName] = useState('')`.
What is a 'lazy initializer' in `useState`, and when should you use it?
Passing a function like `useState(() => expensiveComputation())`. The function runs only on the initial render, avoiding an expensive computation on every re-render.
What happens to a component when its state is updated with the setter?
React schedules a re-render of the component (and its children), reflecting the new state value in the returned JSX.
Why must you never mutate state directly, e.g. `state.value = 5`?
React detects changes by comparing references (identity), not deep contents. Direct mutation doesn't trigger a re-render and can cause stale/inconsistent UI. Always call the setter with a new value/object.
How do you correctly update state that depends on the previous state?
Use the functional updater form: `setCount(prev => prev + 1)`. This uses the latest queued state rather than a possibly stale closure value.
Why can calling `setCount(count + 1)` multiple times in one event handler fail to increment as expected?
All calls read the same stale `count` from the render's closure, so they set the same value. Using `setCount(c => c + 1)` for each call correctly applies sequentially.
How do you update a single property of an object stored in state?
Create a new object copying the old one and overriding the property: `setUser(prev => ({ ...prev, name: 'Ann' }))`.
How do you add an item to an array held in state without mutating it?
Return a new array: `setItems(prev => [...prev, newItem])`. Avoid `push`, which mutates in place.
How do you remove an item from a state array immutably?
Use a non-mutating method that returns a new array, e.g. `setItems(prev => prev.filter(item => item.id !== id))`.
Is React state update synchronous or asynchronous within event handlers?
Effectively asynchronous: React batches updates and applies them before the next render, so the state variable does not change immediately after calling the setter.
What is 'batching' of state updates in React?
React groups multiple state updates that occur in the same event (and, in React 18+, in promises/timeouts too) into a single re-render for performance.
If you call `setValue(x)` with a value equal (by `Object.is`) to the current state, what does React do?
React bails out and skips re-rendering the component, since the state reference/value has not changed.
When should you use multiple separate `useState` calls versus one object?
Use separate state variables when the pieces of state are independent and change separately; group into one object/reducer when they change together or are logically related.
Can you call `useState` multiple times in one component?
Yes. Each call creates an independent state variable, e.g. `const [name, setName] = useState('')` and `const [age, setAge] = useState(0)`.
Why must Hooks like `useState` not be called inside loops, conditions, or nested functions?
React relies on a consistent call order across renders to associate each Hook with its state. Conditional calls break this order (the Rules of Hooks).
What are the two main Rules of Hooks?
1) Only call Hooks at the top level (not in loops/conditions/nested functions). 2) Only call Hooks from React function components or custom Hooks.
What is `useReducer` and what does it return?
A Hook for managing state via a reducer function. `const [state, dispatch] = useReducer(reducer, initialState)` returns the current state and a `dispatch` function.
Show the other 30 State Management flashcards
When is `useReducer` preferred over `useState`?
When state logic is complex, involves multiple sub-values, or the next state depends on the previous one via many action types—centralizing transitions in one reducer improves clarity and testability.
What is the signature of a reducer function?
`(state, action) => newState`. It takes the current state and an action, and returns the new state.
What key rule must a reducer function obey regarding purity?
A reducer must be a pure function: no side effects, no mutation of arguments, and it must return a new state object based solely on `state` and `action`.
What is an 'action' in the `useReducer` pattern?
A plain object describing what happened, conventionally with a `type` field and optional `payload`, e.g. `{ type: 'increment', payload: 5 }`.
How do you trigger a state change with `useReducer`?
Call `dispatch(action)`, e.g. `dispatch({ type: 'increment' })`. React runs the reducer with the current state and the action to compute the next state.
What are the arguments of `useReducer(reducer, initialArg, init)`?
`reducer` (the `(state, action) => newState` function), `initialArg` (initial state or seed), and an optional `init` function for lazy initialization computed as `init(initialArg)`.
Why use the optional `init` (third) argument of `useReducer`?
For lazy initialization: the initial state is computed by `init(initialArg)` only on the first render, and it also enables resetting state (e.g. in response to an action).
Show a typical reducer handling multiple action types.
```js function reducer(state, action){ switch(action.type){ case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error('Unknown action'); } }```
Why is a `switch` statement commonly used inside a reducer?
To branch on `action.type` and return the appropriate next state for each action, keeping all transition logic in one readable place.
In a reducer, why do you return `{ ...state, field: newValue }` instead of mutating `state`?
To preserve immutability: returning a new object lets React detect the change by reference and keeps the reducer pure and predictable.
Compare `useState` and `useReducer` at a high level.
`useState` is simpler for independent/simple state; `useReducer` centralizes complex transition logic, is easier to test, and is preferable when many actions update related state.
Does `dispatch` from `useReducer` have a stable identity across re-renders?
Yes. React guarantees the `dispatch` function identity is stable, so it can be safely omitted from effect/callback dependency arrays and passed down without causing re-renders.
What problem does the Context API solve?
It avoids 'prop drilling' by letting you share data (theme, auth, locale, etc.) across the component tree without manually passing props through every intermediate level.
How do you create a Context?
Call `const MyContext = React.createContext(defaultValue)`, which returns a Context object containing a `Provider` (and, historically, a `Consumer`).
What is the purpose of the `defaultValue` argument in `createContext(defaultValue)`?
It is the value received by consumers only when there is no matching Provider above them in the tree. It is not used when a Provider is present.
How do you provide a context value to a subtree?
Wrap the subtree in the Provider and set its `value` prop: `<MyContext.Provider value={data}>{children}</MyContext.Provider>`.
How do you consume a context value in a function component (modern way)?
Call the `useContext` Hook: `const value = useContext(MyContext)`. It reads the value from the nearest matching Provider above.
What determines which value `useContext` receives?
The `value` prop of the nearest `MyContext.Provider` ancestor in the tree. If none exists, it receives the context's `defaultValue`.
When does a component that calls `useContext` re-render?
Whenever the Provider's `value` changes (compared with `Object.is`), every consumer of that context re-renders.
Why can passing a new object literal as `value` (e.g. `value={{a, b}}`) cause performance issues?
A new object is created every render, so its reference always changes, forcing all consumers to re-render. Memoize it with `useMemo` to keep a stable reference.
How do you combine `useReducer` with Context to build a lightweight global store?
Create the reducer state with `useReducer` at a top-level provider, then pass both `state` and `dispatch` through Context so any descendant can read state and dispatch actions.
What was the older render-prop way to consume context before Hooks?
`<MyContext.Consumer>{value => /* render using value */}</MyContext.Consumer>`, which uses a function-as-child (render prop).
Can a component consume multiple contexts?
Yes. Call `useContext` once per context, e.g. `const theme = useContext(ThemeContext); const user = useContext(UserContext);`.
Can Providers of the same context be nested?
Yes. A consumer reads the value from the nearest Provider ancestor, so inner Providers override outer ones for their subtree.
Why should the argument to `useContext` be the Context object itself, not the Provider?
`useContext(MyContext)` expects the Context object returned by `createContext`; passing `MyContext.Provider` or `.Consumer` is incorrect and will not work.
What is 'lifting state up' in React?
Moving shared state to the closest common ancestor of the components that need it, then passing it down via props so they stay in sync.
How does immutability enable React's efficient change detection?
Because React compares references with `Object.is`, replacing state with a new object/array signals a change in O(1), avoiding deep comparison of contents.
What is the difference between `state` from `useState` and a value from `useContext`?
`useState` state is local and owned by the component; `useContext` reads a value provided by an ancestor Provider and is shared across the subtree.
How can you provide both state and an updater through a single Context cleanly?
Pass an object `value={{ state, dispatch }}` (or `{ value, setValue }`) from the Provider, ideally memoized, so consumers can both read and update shared state.
After calling `dispatch(action)`, is `state` updated immediately in the same function scope?
No. Like `useState`, the update is scheduled; the `state` variable in the current render's closure keeps its old value until the next render.
ReactJS State Management FAQ
What is in the ReactJS State Management syllabus?
ReactJS State Management is split into 3 chapters: useState Hook, useReducer Hook and Context API. Together they contain 9 topics.
How many chapters are in ReactJS State Management?
3 chapters, containing 9 topics. The largest chapter is useState Hook, with 3 topics.
Are there flashcards for ReactJS State Management?
Yes — a 50-card State Management deck, printed in full in the flashcards section of this page and available in the Examius app with spaced repetition. The free plan covers one exam of your choice, including its flashcards; Examius Pro, a one-time purchase, unlocks every other exam and deck.