#Timers#State

Sequential Progress Bars

Clicking Add appends a progress bar, and the bars fill strictly one at a time. A queueing problem disguised as an animation.

By Pratik RaiMedium

Build a small feature where each click on Add appends a progress bar, and the bars fill one at a time — each taking about two seconds — with anything added mid-fill waiting its turn.

It reads like an animation exercise and is really a queueing exercise. The version most people write first gives every bar its own timer at the moment it is created, which fills them all simultaneously; no adjustment to the duration fixes that, because the bug is that nothing tells a new timer to wait.

Inverting the design solves it completely: a single interval that, on each tick, finds the one unfinished bar and advances only that. Because bars are appended and never reordered, the array is the queue — the first bar below 100% is its front — so no separate queue structure is needed at all.

What the interviewer is watching for is whether you notice the queue is already in your data, whether the interval stops when there is nothing to do, and whether your dependency array avoids rebuilding the timer on every tick. The natural follow-up is a concurrency limit: fill three at a time. That is a one-line change with a single driver, and a rewrite with a timer per bar.

Goal: Fill one bar at a time, in creation order, with new bars queueing behind the ones already waiting.

Source

Frequently asked questions

Why do all the bars fill at once in my implementation?
Because each bar got its own timer when it was created, and nothing tells a new timer to wait for the ones before it. Drive everything from a single interval that advances only the one unfinished bar.
How do you queue the bars without a separate queue?
The array already is the queue. Bars are only ever appended, so the first one below 100% is the oldest unfinished bar — `findIndex` gives you the active one directly.
Why should the interval stop when everything is finished?
An interval ticking against an idle component is wasted work, and without an early return the effect tears itself down and rebuilds on every state change. Return early when no bar is unfinished.
What is the usual follow-up question?
A concurrency limit — fill three bars at a time instead of one. With a single driver that is a small change to how many unfinished bars you advance per tick; with a timer per bar it is a rewrite.

Related Challenges

Continue learning with these related challenges

View All
React

File Explorer

Build a nested folder tree from nothing — expand, collapse, and add files and folders at any depth.

React · JavaScriptPratik Rai ·

React

Seat Booking Grid

A cinema seat picker: rows at different prices, sold seats, a selection limit and a running total.

React · JavaScriptPratik Rai ·

React

Image Carousel

Create an interactive image carousel in React with smooth slide transitions, navigation arrows, dot indicators, autoplay, and touch/swipe support for mobile devices.

React · JavaScriptPratik Rai ·