Building a Simple Offline-First Task List with React and LocalStorage
This challenge focuses on implementing a basic offline-first state management pattern in a React application. The goal is to create a simple task list that persists data locally using localStorage, allowing the application to function even when the user is offline. This demonstrates a fundamental concept for building robust web applications that provide a seamless user experience regardless of network connectivity.
Problem Description
You are tasked with building a React component that manages a list of tasks and persists them to localStorage. The component should allow users to:
- Add a new task: A text input field and an "Add Task" button should allow users to add new tasks to the list.
- View the task list: The current list of tasks should be displayed.
- Mark a task as complete: Each task should have a checkbox that, when toggled, marks the task as complete. Completed tasks should be visually distinct (e.g., strikethrough).
- Persist data to
localStorage: The task list should be automatically saved tolocalStoragewhenever it changes. - Load data from
localStorageon component mount: When the component initially mounts, it should retrieve the task list fromlocalStorageand populate the UI.
Key Requirements:
- Use TypeScript for type safety.
- Utilize React state to manage the task list.
- Employ
localStoragefor persistent storage. - Ensure the application functions correctly both online and offline.
- Handle the case where
localStorageis unavailable (e.g., due to browser settings).
Expected Behavior:
- On initial load, the component should attempt to retrieve the task list from
localStorage. IflocalStorageis empty or unavailable, the list should be initialized as empty. - Adding a new task should update the React state and immediately save the updated list to
localStorage. - Toggling a task's completion status should update the React state and immediately save the updated list to
localStorage. - The UI should reflect the current state of the task list, including the completion status of each task.
- If
localStorageis unavailable, an appropriate error message should be displayed to the user (e.g., "Unable to save tasks locally.").
Edge Cases to Consider:
localStorageis full: While unlikely in a simple task list, consider how your code might handle this (e.g., by displaying a message to the user).localStorageis cleared by the user: The application should gracefully handle the loss of data.- Browser settings prevent
localStorageusage: Provide a fallback mechanism or informative message. - Empty task list: The UI should handle an empty task list gracefully.
Examples
Example 1:
Input: Initial state is empty, user adds "Buy groceries" and "Walk the dog".
Output: Task list displays:
- [ ] Buy groceries
- [ ] Walk the dog
localStorage contains: ["Buy groceries", "Walk the dog"]
Explanation: The initial state is empty. Two tasks are added, updating the state and saving to localStorage.
Example 2:
Input: localStorage contains ["Do laundry", "Pay bills"]. User marks "Do laundry" as complete.
Output: Task list displays:
- [x] Do laundry (strikethrough)
- [ ] Pay bills
localStorage contains: ["Do laundry", "Pay bills"] (The content remains the same, but the UI reflects the completed status)
Explanation: The component loads tasks from localStorage. One task is marked complete, updating the state and saving the updated list to localStorage.
Example 3:
Input: localStorage is unavailable (e.g., due to browser settings).
Output: Task list displays:
- An error message: "Unable to save tasks locally."
Explanation: The component detects that localStorage is unavailable and displays an appropriate error message.
Constraints
- The task list should be stored as an array of strings in
localStorage. Each string represents a task. - The application should be responsive and provide a reasonable user experience.
- The component should be relatively simple and focused on the core offline-first functionality. No complex styling or UI frameworks are required beyond basic React components.
- The maximum number of tasks is limited to 100. (This is a practical consideration for
localStoragesize, though not strictly enforced in the evaluation).
Notes
- Consider using
useEffectto handle side effects like loading and saving data tolocalStorage. - Think about how to handle errors gracefully, especially when interacting with
localStorage. - Focus on the core logic of persisting and retrieving data. Styling and advanced UI features are not the primary focus of this challenge.
- Use a functional component with React Hooks.
- The key is to ensure that the task list is consistently synchronized between the React state and
localStorage, providing a seamless offline experience.