A general guideline of good UX is to have what’s on screen reflect the state of the system. When you’re dealing with large applications (especially single page apps), you end up having data pulled from all different types of sources.
A typical pattern is to have each component be responsible for fetching (or crunching) their own data. While these components are busy doing something, we need to display that state back to the user.
It almost goes with out saying, but at the beginning of development, design, UX, and engineering need to work together on a clear loading solution. By figuring this out at the beginning of your development, rather than the end, makes it much easier to implement.
This means requires gathering constraints, requirements, and implementing the experience for the user — in other words, User Interaction Engineering.
Once a pattern to for the loading experience has been figured out, it’s important to abstract it so it plays nicely with other code.
The simplest way to do this is with a simple loader component that wraps the component that’s loading. Let’s call it the
<PrettyLoader>: “pretty” because it’s going to have fancy CSS animation added by the design department; “loader” because the component is in the loading state to the user.
This simple component just adds or removes a `hidden` class based on state (which is one of many ways to handle this functionality). It’s important to think about the structure of the component’s state object. These examples assume that the
loading attribute on the state object is
boolean, but different data types might be more appropriate for your application. (More on this later).
Simply wrap other components in
<PrettyLoader> to use the loader component.
Of course, nothing works right now since there is no way of changing
<PrettyLoader>'s state. But this is easy as well. If you’re using redux, you can connect the
<PrettyLoader> to a store.
This has the added benefit of simplifying the component since you don’t need state at all and can remove the constructor.
(This example assumes the
loader event is a CustomEvent.)
loading variable isn’t just limited to being a Boolean datatype either. In some situations, such as many different components asynchronously loading their data on the same page, it would be appropriate assign the
loading variable to a different datatype, such as an array, or even an array of objects.
For example, imagine a single page app makes calls to dozens of endpoints throughout the course of a user journey. If the endpoints are defined in a static class, along with other metadata, this can be fed to the
By passing a descriptive object to your ajax class (instead of a string with just the endpoint), and dispatching the custom
loader event from that ajax class, you can send the
loading_message up to your
<PrettyLoader>. Now thanks to a little abstraction, your code is organized and users can receive rich details about what is happening.
<PrettyLoader> can also be a purely functional component.
If you’re using redux, you can setup your loading metadata (i.e. the
loading variable) as a store.
(Personally, I think this is overkill and it’s simpler to have
<PrettyLoader> be event based instead of composed. Also note how the content is hidden in a different way, which has nothing to do with redux.)
<PrettyLoader> is a simple engineering pattern that can be quite powerful if you want — for example, your pretty loader could store diffs of client data and offer an undo button!
Hopefully, you will find that having a component based approach to handling loading operations is the way to go!
Special thanks for proofreading and feedback to the folks in the #react chatroom on Team Gun.io