Todos reducer
Implement todosReducer(state, action). state is an array of { id, text, done }. Actions: { type: 'add', id, text } appends a todo that is not done; { type: 'toggle', id } flips done; { type: 'remove', id } deletes it; { type: 'clearCompleted' } removes the done ones. Never change the input: the tests freeze it, so a mutation throws. Return a new array, with new objects only for the todos that changed. For an unknown action return the same state. The answer shows the final state, whether it is the same reference as the input, and how many todo objects were reused.
Start from
function todosReducer(state, action) {
// Return the next state without changing the input.
}Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1
A switch on action.type with one line per case: spread for add, map for toggle, filter for remove and clearCompleted.
Hint 2
In toggle, return the same todo object for the ones that did not change. That is what lets React.memo skip them.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
JavaScript
function todosReducer(state, action) {
switch (action.type) {
case "add":
return [...state, { id: action.id, text: action.text, done: false }];
case "toggle":
return state.map((todo) =>
todo.id === action.id ? { ...todo, done: !todo.done } : todo,
);
case "remove":
return state.filter((todo) => todo.id !== action.id);
case "clearCompleted":
return state.filter((todo) => !todo.done);
default:
return state;
}
}What an interviewer looks for
useReducer and Redux both rest on this. Interviewers check immutability, and whether unchanged items keep their identity so memoized rows do not re-render.