Build a Real-Time Event Feed Dashboard
CitadelFrontend Engineer · Technical ScreenLast updated
Implement a robust React hook to manage a high-frequency, real-time event feed dashboard with pause/resume controls, out-of-order de-duplication, memory bounding, and rolling time-window statistics.
Real-Time Event Feed Manager
In trading environments, market feeds emit high-velocity bursts of messages that can arrive out of order or with duplicate sequence IDs. Your task is to implement the core state logic for a real-time event feed dashboard via a React hook named useEventFeed.
Requirements
- Subscription & Cleanup: Subscribe to the provided
subscribefunction on mount, and invoke the returned teardown function on unmount. - De-duplication & Ordering: Deduplicate events by their unique
id. Events must be presented in descending order oftimestamp(newest first), even if they arrive out of order. - Memory Bounding: Retain at most
maxEventstotal items in memory. Discard the oldest events when this threshold is exceeded. - Pause / Resume: Expose
isPaused,pause(), andresume(). When paused, newly arriving events should be buffered in the background and integrated seamlessly upon resume without dropping events (subject tomaxEvents). - Rolling Window Statistics: Maintain statistics for the last
windowMs(default 30 seconds): total event count, event rate (events/second), and average numeric value. These stats must stay accurate even during quiet periods where no new events arrive.
Function Signature
interface FeedEvent {
id: string;
type: 'order' | 'trade' | 'alert';
timestamp: number; // millisecond timestamp
value: number;
}
interface UseEventFeedOptions {
subscribe: (onEvent: (event: FeedEvent) => void) => () => void;
windowMs?: number; // default: 30000
maxEvents?: number; // default: 200
statIntervalMs?: number; // default: 1000
}
interface UseEventFeedResult {
events: FeedEvent[];
eventsByType: Record;
stats: {
count: number;
ratePerSecond: number;
averageValue: number;
};
isPaused: boolean;
pause: () => void;
resume: () => void;
}
function useEventFeed(options: UseEventFeedOptions): UseEventFeedResult;
Example
// Event Stream arrives:
// t = 1000: { id: 'e1', type: 'trade', timestamp: 1000, value: 50 }
// t = 1050: { id: 'e3', type: 'trade', timestamp: 3000, value: 100 } (arrived early)
// t = 1100: { id: 'e2', type: 'order', timestamp: 2000, value: 70 }
// t = 1150: { id: 'e1', type: 'trade', timestamp: 1000, value: 50 } (duplicate)
// Current events list after t = 1150:
// [e3, e2, e1] (sorted descending by timestamp; e1 deduplicated)
Constraints & Edge Cases
maxEventscan range from10to5000.- Incoming bursts can deliver up to 500 events within a single 50ms window.
- Timestamps are positive integers (epoch ms).
- Quiet windows: if no events arrive for 35 seconds,
stats.countandstats.ratePerSecondmust decay to0without requiring user interaction.
Hints
Hint 1
Avoid updating component state on every single incoming event during high-frequency bursts by batching updates using a ref buffer and `requestAnimationFrame` or a short interval.
Hint 2
Use a `Set` or hash map to maintain known event IDs to achieve O(1) deduplication before inserting into a sorted structure or array.
Hint 3
A background interval is necessary to periodically evict expired events from rolling calculations during periods when the feed goes quiet.
Follow-up questions
- How would you throttle React re-renders if the WebSocket feed fires 1,000 events per second?
- How can you avoid stale closures in your subscription callback without continuously resubscribing?
- If `maxEvents` is increased to 50,000, how would you optimize the binary search insertion and rendering performance?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.