As developers, we all underestimate how complex can be to manage loaders in a web application.
While the good old setting boolean method works, it becomes redundant and insufficient fast when requirements like needing separate loaders for different processes and/or needing one loader to wait for multiple processes emerge.
While the usage in example 1 works fine with one async method or one or more synchronous methods, it starts to get problematic when two or more asynchronous methods need to show the same loading when in progress. See example 2 below:
In example 2, two async methods need to load data in parallel. What happens here is once the first method passes “await” isLoading sets to false while the other one is still in progress. So the spinner is not working when it’s supposed to work.
The solution that I came up with for this particular problem was to write a reactive loading service that I can both manage one particular loader or many loaders at once.
Here is the loading service that I came up with:
Here we create a reactive TLoadingKey (string literal type) Set to ensure there are no duplicate keys.
Here we create a reactive (in case we need reactivity later) Map with the TLoadingKey key type and NodeJS.Timeout value type. More on timeouts later.
This is the start loading method that we expose. We append the key to the loadings set. And, in case the loading does not stop for that key, we add a timeout for that key and remove the key from the loadings.
The stopLoading method is pretty much the reverse of the startLoading method.
Optionally, you can give a string literal type like above. And again, optionally you can define some type prefix and such.
What I like to do with services like this is to export the instance from a file called singletons.ts.
The code above is a rewrite of example 2 using the loading service. You might not need prefixes like ‘main-loader’. You can customize the key type as Symbol, plain string, or number.
Alternatively, you can implement the Loading service as a hook and use it like that.
Before closing, this approach can be implemented in any framework with its reactive utilities. In React you can use useState instead of reactive, in Angular it should work just fine if the class is marked with the Injectable decorator.
Thank you for reading.