# 7090 MINBuild an External Store
# 70
90 MIN
Overview
Build the external metrics store — an in-memory object on the client that holds the current state — that powers the provided dashboard, implementing the subscribe/getSnapshot contract, polling, pause/resume, and stale-response protection.
Solution preview
Here's the result you'll build by completing this challenge.
Requirements
createMetricsStore(fetcher)returns an object withsubscribe,getSnapshot,start,refresh,pause, andresume.- The initial snapshot is
{ metrics: [], updatedAt: null, status: "idle", error: null }. getSnapshotreturns the same object reference until the state changes.subscribe(listener)registers a listener and returns a function that removes it.- Subscribers are notified after every state change.
start()fetches immediately, then every five seconds, and returns a cleanup function that stops polling.- Calling
start()while polling is already active does not create a second interval. - While a request started by
refresh()is in flight and the store is not paused, the status isloading. - When the store is not paused,
refresh()ends inlivewith the new metrics andupdatedAt, or inerrorwith the message. - When a request fails, the last successful metrics remain in the snapshot.
- After an error, the next poll retries the request.
- When two requests overlap, only the response from the latest request is applied.
pause()stops polling, sets the status topaused, and ignores an in-flight response.resume()fetches immediately, restarts polling, and does nothing if the store is not paused.- A manual
refresh()while paused updates the data but keeps the statuspaused. - The
dashboardStoresingleton is exported and used by the providedApp.tsx.
Notes
- This challenge builds the store consumed in
069-live-dashboard. The providedApp.tsxis already wired, so read it first to see the exact API the store must expose. - The state has to live outside React, but
getSnapshotis compared by reference. Think about what that means for every update. - There are two clocks in this exercise: the polling interval and the request latency. Consider what happens when one finishes while the other is still running.
- React StrictMode mounts effects twice in development. Keep that in mind when an effect starts a timer.
- Pausing is not only about stopping the interval; think about what to do with a request that is already in flight.
- A listener can unsubscribe while others remain; the notification mechanism should handle that safely.
- APIs:
useSyncExternalStore,setInterval, Page Visibility API.
Tests
- exports the dashboardStore singleton
- renders the provided dashboard with the store
- starts with an idle snapshot and a stable reference
- notifies subscribers when the state changes
- stops notifying after unsubscribing
- fetches immediately when started
- shows a loading status while a request is in flight
- polls every five seconds
- does not create duplicate intervals when start is called twice
- stops polling after stop is called
- keeps the last metrics when a request fails
- recovers on the next poll after an error
- discards a stale response that arrives after a newer one
- pauses polling and marks the dashboard as paused
- ignores an in-flight response that arrives after pausing
- resumes with an immediate fetch and restarts polling
- stays paused when refreshed manually while paused
- keeps the snapshot reference stable between updates