# 1115 MINuseToDo & useLocalStorage Hooks
# 11
15 MIN
Overview
Refactor the existing ToDo app by moving all task-related logic into a custom hook useTodo, and persist tasks in localStorage through a separate useLocalStorage hook.
Requirements
- Move the current ToDo logic (state, handlers, etc.) into a custom hook called
useTodo. - Implement a
useLocalStoragehook responsible for synchronizing the ToDo list withlocalStorage. - The ToDo list must:
- Load saved tasks from
localStorageon mount. - Save updated tasks to
localStoragewhenever the list changes.
- Load saved tasks from
- The
useTodohook should expose:- The list of tasks.
- Functions to:
- Add a task when submitting the form.
- Delete a task.
- Toggle a task's completion status, applying a line-through style when completed.
- Clear completed tasks.
- Show the "Clear complete" button only when there is at least one completed task.
Notes
- The main goal is to separate responsibilities:
useTodohandles app logic.useLocalStoragehandles persistence.
- The starter app is already functional: add, toggle, delete and clear all work in
App.tsx, so the behavior tests already pass. The tests verify behavior, not implementation — they don't care whether the logic lives inAppor in a custom hook. - The real objective is the refactor: extract all task logic into
useTodoand move persistence intouseLocalStoragewithout changing the UI. The persistence test (06) is the only one failing with the starter — it passes once tasks are saved to and loaded fromlocalStorage. - A natural API for
useTodois to return the list, a derivedhasCompletedflag, and the handlers the UI needs:The exact names are up to you — the tests only check behavior. - Keep your hooks pure and reusable — avoid ToDo-specific logic in
useLocalStorage. - When initializing state from
localStorage, remember to handle missing or malformed data safely. - The UI code should not change beyond using
useTodoinstead of local state. - How you manage the input is up to you:
- Controlled: store the input value in state and expose it (value + setter) from
useTodo. - Uncontrolled: read the value from the form on submit (e.g.
FormData) and reset the form. The reference solution does this, souseTododoesn't expose an input setter.
- Controlled: store the input value in state and expose it (value + setter) from
Tests
- adds a task when submitting the form
- toggles task completion and apply line-through when checkbox is clicked
- deletes a task when delete button is clicked
- shows only 'Clear complete' button when there is at least one completed task
- clears completed tasks when 'Clear complete' is clicked
- persists tasks in localStorage across mounts