Set a Minimum Display Time for Material-UI Skeleton Loader

Jon Middaugh
The Clever Dev
Published in
3 min readAug 5, 2020

Let’s configure a Material-UI Skeleton Loader to display for 1 second OR the loading time of an API call, whichever is greater.

Photo by NordWood Themes on Unsplash

Typically users don’t need a loading icon if load time is less than 1 second, but if you are uncertain how long an API may take to respond, you may want to avoid flashing a component on the screen before showing a loading indicator.

Alternatively, you could show nothing at all for one second before choosing to show a loading indicator. Or you could show the indicator immediately, which is what I will show in this demo. Let’s get to coding!

Here’s the finished CodeSandBox. We’ll walk through the code step-by-step below.

We’ll start with these constants:

const [minimumTime, setMinimumTime] = useState(500); 
const [minimumTimeElapsed, setMinimumTimeElapsed] = useState(true);
const [loading, setLoading] = useState(false);

If this weren’t a demo, you would have a const minimumTime = 500; (or whatever desired value) instead of the state const above. In this demo, the minimum time is adjustable by the user.

minimumTimeElapsed is one of the two checks performed by the logic to determine if the <Skeleton /> should be shown. loading is the other variable checked, and it is true or false depending on if our simulated API call has completed.

Below is the ternary statement in our JSX that uses the two constants mentioned above. It either shows the <Skeleton/> component or the <JobTable/> component (made with material-table) if the user-specified minimum visible time has not elapsed or the simulated loading has not finished.

{ 
!minimumTimeElapsed || loading
? <Skeleton style={{ height: 200 }} />
: <JobTable />
}

Given that our hypothetical user requirements state that it should be visible if a) a minimum time has not elapsed, or b) the API call has not completed yet, we need a way to determine when to flip the state. The state is time based, so we will have to use setTimeout within a callback:

const restartTimeout = useCallback(() => 
{
setMinimumTimeElapsed(false);
setTimeout(() => {
setMinimumTimeElapsed(true);
}, minimumTime);
//simulate random load time between 0 and 5 seconds const
randomLoadTime = Math.random() * 5000;
setLoading(true);
//simulate loading
setTimeout(() => {
setLoading(false);
}, randomLoadTime);
}, [setMinimumTimeElapsed, setLoading, minimumTime]
);

The restartTimeout function takes a user-specified minimum time and flips minimumTimeElapsed to true when the setTimeout callback is called.

The setTimeout that flips loading to false is only necessary for demo purposes. In a real situation, your code would instead likely be observing a loading observable in a store.

The Result

Our <Skeleton /> now shows for at least half a second or the loading time of the simulated API call, whichever is longer. Our constants are clearly named so the logic is conveyed to future devs looking at this code.

If you can confirm that the logic is correct and the code is clean, consider your work a job well done.

Get developer-specific side hustle tips from me here.

--

--

Jon Middaugh
The Clever Dev

I have been: individual contributor | tech lead | manager | JS boot camp teacher | community college instructor.