Command Palette

Search for a command to run...

Hectal
Phase 9Intermediate10 of 28 in React

Context and Reducers

Pass data deep without drilling props, avoid context re-render traps, move state logic into reducers, and combine both into a small app-wide store.

So far, data has moved through your app one way: down through props. That works well until a value is needed ten levels deep and every component in between must carry it. This phase starts with that problem, prop drilling, and the first fix most people skip: composition with children. Then it introduces context, React's way to make a value available to a whole part of the tree without passing it by hand, including the React 19 <Context value> provider and the older .Provider you'll meet in existing code.

Context is easy to start and easy to misuse. You'll watch, with render logs, how every component that reads a context renders again when its value changes, and fix it by memoising the value and splitting one context into two. You'll also learn when not to use context at all.

The second half moves state logic into one place with useReducer: a pure function that takes the current state and an action and returns the next state. You'll compare it honestly with useState, test reducers as plain functions, use Immer inside a reducer, and finish by combining a reducer with two contexts (state and dispatch) and custom hooks into a small app-wide store. That's the pattern behind Redux and many real apps, and the bridge to Phase 15.

0/6 · 0%
6 topics ~3 h 24 code blocks & diagrams
Start with the first topic
1
9.1

The Prop Drilling Problem

Prop drilling is passing a prop through components that don't use it, only so a component deep below can read it; it's fine for two or three levels, and when it gets painful the first fix is composition: pass finished JSX down as children instead of the raw data.

23 min 3 code practice

2
9.2

Context: Passing Data Deeply

Context lets a component make a value available to everything below it without passing props: create it with createContext(defaultValue), provide it with <MyContext value={...}> (React 19) or <MyContext.Provider value={...}> (older code), and read it with useContext(MyContext), which returns the value from the nearest provider above.

24 min 4 code practice

3
9.3

Context Patterns and Pitfalls

Context fits values many distant components read and that change rarely, such as the theme, the signed-in user and the locale; every reader re-renders whenever the value changes, so keep the value stable with useMemo/useCallback, split values that change at different rates into separate contexts, and don't use context for fast-changing or server data.

29 min 4 code practice

4
9.4

useReducer: State Logic in One Place

useReducer(reducer, initialState) keeps a component's state like useState, but every change goes through one pure function, reducer(state, action), that returns the next state; event handlers only dispatch actions that describe what happened.

28 min 4 code practice

5
9.5

useState or useReducer?

Both hold the same kind of local state; choose useState for simple, independent values and useReducer when many handlers update the same state in related ways, when you want to read and debug every change as an action, or test the logic as a plain function, and add Immer when the updates are deeply nested.

28 min 5 code practice

6
9.6

Scaling Up with a Reducer and Context

Combine a reducer (all the update logic) with context (reach anywhere): a provider component owns useReducer and puts state and dispatch in two separate contexts, and small custom hooks such as useTasks() and useTasksDispatch() let any component read or update the store without props.

28 min 4 code practice

Practise this phase

Hands-on exercises: write the code, see your page live, and press Check to have it tested automatically.