Hone logo
Hone
Problems

Building Eventually Consistent State in a React Application

Many real-world applications require data synchronization across multiple sources or users. This challenge focuses on implementing a simplified version of eventually consistent state management in a React application. You'll build a component that allows users to update a shared counter, and these updates are propagated asynchronously, demonstrating the principles of eventual consistency.

Problem Description

You are tasked with creating a Counter component that displays a shared counter value. Multiple instances of this Counter component can exist on the page, each representing a different user's view of the counter. Users can increment the counter using a button. The updates to the counter are not immediately reflected across all instances; instead, they are applied asynchronously after a short delay, simulating network latency or distributed systems behavior. The goal is to create a React component that manages this eventually consistent state effectively.

Key Requirements:

  • Shared State: The counter value should be considered a shared state across all instances of the Counter component.
  • Asynchronous Updates: Incrementing the counter should not immediately update all instances. Introduce a delay (e.g., 500ms) before applying the update.
  • Visual Indication: While an update is propagating, provide a visual indication (e.g., a loading spinner or a message) to the user that the change is in progress.
  • Reconciliation: Ensure that when an update finally propagates, all instances of the Counter component display the same, latest value.
  • TypeScript: The solution must be written in TypeScript.

Expected Behavior:

  1. When a user clicks the "Increment" button on one Counter component, the component should display a loading indicator.
  2. After a 500ms delay, the counter value on that component should increment.
  3. After another 500ms delay, the counter value on all other Counter components should also increment.
  4. The loading indicator should disappear after the update is applied to the component itself.

Edge Cases to Consider:

  • Rapid Increments: What happens if a user rapidly clicks the "Increment" button? Should updates be queued or processed immediately? (For simplicity, immediate processing is acceptable).
  • Multiple Concurrent Updates: If multiple users increment the counter simultaneously, how are the updates reconciled? (The last update to propagate wins is acceptable for this simplified scenario).

Examples

Example 1:

Input: Two Counter components, both initially displaying 0. User clicks "Increment" on the first component.
Output:
    - First component: Displays "Loading..." then updates to 1.
    - Second component: Remains at 0 for 500ms, then updates to 1.
Explanation: The first component initiates the update, displays a loading state, updates itself, and then propagates the update to the second component after a delay.

Example 2:

Input: Three Counter components, all initially displaying 5. User clicks "Increment" on the second component.
Output:
    - First component: Remains at 5 for 500ms, then updates to 6.
    - Second component: Displays "Loading..." then updates to 6.
    - Third component: Remains at 5 for 500ms, then updates to 6.
Explanation: The second component initiates the update, displays a loading state, updates itself, and then propagates the update to the other components after a delay.

Example 3: (Edge Case - Rapid Clicks)

Input: One Counter component initially displaying 0. User rapidly clicks "Increment" five times in quick succession.
Output:
    - The counter will increment to 5, with each increment taking 500ms.  Loading indicators will appear and disappear sequentially for each click.
Explanation:  Each click triggers an update, which is processed sequentially with the 500ms delay.

Constraints

  • Delay: The delay for asynchronous updates should be 500ms.
  • State Management: You can use React's built-in useState hook for local component state. A context provider or other global state management solution is not required for this simplified example.
  • Rendering: The component should re-render correctly after each update.
  • TypeScript: The code must be valid TypeScript.
  • Performance: While not a primary focus, avoid unnecessary re-renders.

Notes

  • Consider using setTimeout to introduce the asynchronous delay.
  • Think about how to manage the loading state effectively to provide a good user experience.
  • This is a simplified model of eventual consistency. Real-world systems often involve more complex conflict resolution strategies and data replication mechanisms.
  • Focus on demonstrating the core concepts of asynchronous state updates and eventual consistency within a React component.
Loading editor...
typescript