Deliver shared state through context and update it with explicit actions.
Read the explanation, run the worked example, then complete the matching Examples and Assignments tabs. Your original materials remain available alongside these notes.
Understand the idea
A reducer is a pure function: given state and an action, it returns the next state. It should not fetch, start timers or mutate unrelated values. An action names intent such as rate or reset and carries any required payload. This makes the transitions easy to inspect and test.
A context provider makes its value available below it. Your A → B → C exercise demonstrates that B can simply render C without forwarding rating or dispatch. The nearest provider supplies the value. A context update can rerender consumers; it is not automatically a performance optimization.
Run the example
Use a separate React practice project with a Node.js version supported by Vite. Create it once with these commands, then use its development URL. Do not paste this into the Edupoly website’s own source files.
npm create vite@latest react-practice -- --template react
cd react-practice
npm install
npm run dev
Replace src/App.jsx with the following complete example. Keep Vite’s generated src/main.jsx entry point.
src/App.jsx
import { createContext, useContext, useReducer } from 'react';
const RatingContext = createContext(null);
function reducer(state, action) {
switch (action.type) {
case 'rate': return {...state, rating: Math.max(0, Math.min(5, action.value))};
case 'theme': return {...state, dark: !state.dark};
case 'reset': return {...state, rating: 0};
default: return state;
}
}
function C() {
const {state, dispatch} = useContext(RatingContext);
return <section style={{background: state.dark ? '#222' : '#fff', color: state.dark ? '#fff' : '#222', padding: 20}}>
<p>Rating: {state.rating}/5</p>{[1,2,3,4,5].map(n => <button key={n} aria-label={`Rate ${n} stars`} aria-pressed={n === state.rating} onClick={() => dispatch({type: 'rate', value: n})}>{n <= state.rating ? '★' : '☆'}</button>)}
<button onClick={() => dispatch({type: 'theme'})}>Change background</button><button onClick={() => dispatch({type: 'reset'})}>Reset rating</button>
</section>;
}
function B() { return <C />; }
function A() { return <B />; }
export default function App() {
const [state, dispatch] = useReducer(reducer, {rating: 0, dark: false});
return <RatingContext.Provider value={{state, dispatch}}><A /></RatingContext.Provider>;
}
Expected result
Clicking star 4 displays 4/5, changing background preserves the rating, and Reset returns it to zero.
Apply this to your assignments
Use this to complete your A/B/C, background-color and rating assignments. Write down the state before, action and expected state after each click. Test 1, 5, reset and repeated selection.
Your existing examples
- Create a clock using useState hook
- Creating an Increment button using useState and useEffect to show alert after button click.
Open the Examples tab to run or inspect these supplied projects. Their original links are preserved.
Open Assignments for your complete original worksheet. Use the assignment workspace link to submit completed work.
Common mistakes
Do not mutate plain reducer state. A consumer must render beneath the provider, not alongside it.
Check your understanding
- Predict the output before running the example, then compare it with the result panel.
- Explain which value each expression reads and which action changes it.
- Try the boundary cases listed in the practice task and record what you observe.
- Rebuild one matching assignment without copying, then compare behavior with the original example.
Reference
Official documentation for this topic · Vite setup requirements
