Hone logo
Hone
Problems

React Eventually Consistent State Management

This challenge focuses on building a React component that manages state which is updated asynchronously and might temporarily diverge from the source of truth. This is a common pattern in applications dealing with network requests or distributed systems where immediate consistency isn't always feasible or desirable. The goal is to create a user experience that feels responsive while gracefully handling the eventual synchronization of data.

Problem Description

You need to build a React component that displays a list of items and allows the user to toggle a "completed" status for each item. The state update for toggling the status should be simulated as an asynchronous operation (e.g., a network request).

Key Requirements:

  1. Display a list of items: Each item should show its name and its current completion status (e.g., "Pending" or "Completed").
  2. Asynchronous status toggle: When a user clicks on an item to toggle its completion status, an asynchronous operation should be initiated.
  3. Optimistic UI update: The UI should immediately reflect the intended new state (e.g., if toggled from "Pending" to "Completed", the item should appear completed instantly).
  4. Handling eventual consistency:
    • If the asynchronous operation succeeds, the UI remains in the optimistically updated state.
    • If the asynchronous operation fails, the UI should revert to its previous consistent state.
    • During the asynchronous operation, a visual indicator (e.g., a spinner or disabled state) should be shown for the affected item.
  5. Error display: If the asynchronous operation fails, provide a clear visual indication to the user that the operation failed and potentially a reason for the failure.

Expected Behavior:

  • User sees a list of items.
  • User clicks an item to mark it as complete.
  • Immediately, the item visually changes to "Completed," and a loading indicator appears for that item.
  • After a simulated delay (representing network latency), if the operation was successful, the loading indicator disappears, and the item remains "Completed."
  • After a simulated delay, if the operation failed, the item visually reverts to its "Pending" state, the loading indicator disappears, and an error message is displayed for that item.

Edge Cases:

  • Multiple items being toggled concurrently.
  • Network errors occurring during the operation.

Examples

Example 1:

Initial State (UI):

Items:
- Task A (Pending)
- Task B (Pending)

User Action: Clicks on "Task A".

Intermediate State (UI - Optimistic Update + Loading):

Items:
- Task A (Completed) [Loading Indicator]
- Task B (Pending)

Simulated Asynchronous Operation Outcome: Success after 1 second.

Final State (UI):

Items:
- Task A (Completed)
- Task B (Pending)

Explanation: The UI immediately updated to reflect Task A as completed. The simulated network request succeeded, so the state remains updated.

Example 2:

Initial State (UI):

Items:
- Task A (Pending)
- Task B (Pending)

User Action: Clicks on "Task A".

Intermediate State (UI - Optimistic Update + Loading):

Items:
- Task A (Completed) [Loading Indicator]
- Task B (Pending)

Simulated Asynchronous Operation Outcome: Failure (e.g., server error) after 1 second.

Final State (UI):

Items:
- Task A (Pending) [Error Message: "Failed to complete task."]
- Task B (Pending)

Explanation: The UI optimistically updated Task A. However, the simulated network request failed. The UI then reverted Task A to its original "Pending" state and displayed an error message.

Example 3: (Concurrent Operations)

Initial State (UI):

Items:
- Task A (Pending)
- Task B (Pending)
- Task C (Pending)

User Actions:

  1. Clicks on "Task A".
  2. Immediately clicks on "Task C".

Intermediate State (UI - Optimistic Updates + Loading):

Items:
- Task A (Completed) [Loading Indicator]
- Task B (Pending)
- Task C (Completed) [Loading Indicator]

Simulated Asynchronous Operation Outcome:

  • Task A: Success after 1 second.
  • Task C: Failure after 0.5 seconds.

Final State (UI):

Items:
- Task A (Completed)
- Task B (Pending)
- Task C (Pending) [Error Message: "Could not update task."]

Explanation: Both Task A and Task C were optimistically updated. Task A's update succeeded. Task C's update failed, causing it to revert and show an error. Task B was unaffected.

Constraints

  • The list of items will contain between 1 and 20 items.
  • Each item's id will be a unique string.
  • Each item's name will be a string.
  • The completed status will be a boolean.
  • The asynchronous operation simulating the network request should have a random delay between 500ms and 1500ms.
  • The asynchronous operation should have a 20% chance of failing.
  • The component should be built using functional React components and TypeScript.

Notes

  • Consider using React's useState and useEffect hooks.
  • For managing loading and error states per item, you might consider a structure that holds this alongside the item data.
  • Think about how to prevent the user from interacting with an item that is currently in the process of being updated.
  • The asynchronous operation can be simulated using setTimeout and Promise.reject for failure.
  • Success looks like a responsive UI that handles temporary inconsistencies gracefully, providing clear feedback to the user about the status of their actions.
Loading editor...
typescript