Optimistic Updates in a Todo List with React and TypeScript
Optimistic updates enhance user experience by immediately reflecting changes on the UI before the server confirms them. This challenge asks you to implement optimistic updates in a simple React-based todo list application. You'll be updating the UI as if the todo item has been successfully marked as complete, even before the API call returns.
Problem Description
You are tasked with building a React component that manages a list of todo items. Each todo item has a id, text, and completed status. The component should allow users to toggle the completed status of a todo item by clicking a checkbox. Instead of waiting for the server to confirm the update, you should immediately update the UI to reflect the new completed status (optimistic update). After the UI update, you'll make an asynchronous API call to persist the change. If the API call fails, you should revert the UI to its previous state.
Key Requirements:
- State Management: Use React's
useStatehook to manage the list of todo items. - Optimistic Update: Immediately update the UI when a todo item's
completedstatus is toggled. - API Simulation: Simulate an asynchronous API call using
setTimeoutto represent the network request. The API call should randomly succeed or fail (50% chance of success). - Error Handling: If the API call fails, revert the UI to its previous state.
- TypeScript: The entire solution must be written in TypeScript.
- Clear UI: The todo list should display each item with its text and a checkbox indicating its completion status.
Expected Behavior:
- When a user clicks the checkbox for a todo item, the UI should immediately update to reflect the new
completedstatus. - A simulated API call is made.
- If the API call succeeds, the UI remains updated.
- If the API call fails, the UI reverts to its previous state (the checkbox returns to its original state).
- The component should handle an empty todo list gracefully.
Edge Cases to Consider:
- What happens if the API call takes a very long time? (Consider a loading indicator, though not strictly required for this challenge).
- How do you handle potential race conditions if the user toggles multiple items quickly? (A simple approach is sufficient for this challenge; complex debouncing is not required).
- What happens if the initial todo list is empty?
Examples
Example 1:
Input: Initial state: [{ id: 1, text: "Buy groceries", completed: false }]
User clicks the checkbox for "Buy groceries".
Output: UI immediately updates: [{ id: 1, text: "Buy groceries", completed: true }]
API call succeeds.
Final state: [{ id: 1, text: "Buy groceries", completed: true }]
Example 2:
Input: Initial state: [{ id: 1, text: "Walk the dog", completed: true }, { id: 2, text: "Do laundry", completed: false }]
User clicks the checkbox for "Do laundry".
Output: UI immediately updates: [{ id: 1, text: "Walk the dog", completed: true }, { id: 2, text: "Do laundry", completed: true }]
API call fails.
Final state: [{ id: 1, text: "Walk the dog", completed: true }, { id: 2, text: "Do laundry", completed: false }]
Example 3:
Input: Initial state: [] (empty list)
User clicks a non-existent checkbox (no effect).
Output: UI remains empty: []
Constraints
- The API simulation should have a delay of approximately 500ms.
- The API call should have a 50% chance of success.
- The component should render efficiently, even with a large number of todo items (assume up to 100 items).
- The solution must be written in TypeScript.
Notes
- Focus on the optimistic update logic and error handling. Styling is not required.
- You can use a simple
setTimeoutfunction to simulate the API call. - Consider using a temporary state variable to store the previous state before the optimistic update, allowing you to revert if the API call fails.
- Think about how to handle the asynchronous nature of the API call and the need to update the state accordingly.
- The goal is to demonstrate understanding of optimistic updates, not to build a production-ready todo list application.