Enterprise JavaScript
Mo Sayed, Principal UI Developer
7 February 202310 minute read
As reported in the recent survey: State of JS 2022, React is the most popular UI library/framework for developing User Interfaces (UI). As a tool, it continues to evolve with recent developments such as:
Discussion of these is outside the scope of the current article. Rather, I'd like to explore developments in the wider React ecosystem such as:
Each of these is discussed in more detail below.
Application State Management is one of the hardest problems to solve within the UI domain, explaining why there are > 50 libraries dedicated to it, including Redux, MobX, and Zustand. Typically UI state can be divided into two main types:
It has been common practice to treat these the same and bundle them together into a single data store. However, in recent years, luminaries such as KC Dodds & Tanner Linsley have argued that this may not be the best approach
Consider the difference between the two:
These differences offer a host of challenges for the Server State such as:
Based on these differences, it makes sense to separate the 2 kinds of states and treat them differently. A practical approach would be to handle Server-State using libraries for caching and managing Server-State like React Query & SWR.
For Client State, we can do the following:
When using useContext for State Management, it is important to be cautious as it can lead to multiple rendering issues. When a context is high in the component tree, a change to any state held in context could result in excessive re-renders and poor performance. To address this, the React team has proposed the development of a new hook, useSelectedContext, which allows for selecting a 'slice' of the state and only re-rendering when that specific slice changes.
Vanilla React applications suffer from the following problems:
Addressing these deficiencies has led to the emergence of several React-based Server Side Rendering frameworks (SSR), such as Gatsby, Next.js, & more recently Remix. Rendering the page on the Server means that there's less JavaScript being sent across the network which will boost performance. Further having a page delivered to the browser with a lot more content improves SEO. SSR feels like a return to the old day when web pages were generated on the server and has obvious implications such as:
One potential issue with SSR is that it is only as fast as the slowest query. This is because you have to fetch all the content for a page (which could involve several individual queries) before the page can be built on the server and returned to the browser. Fortunately, recent developments in React 18 offer a solution to this in the form of React Server Components (RSC).
This feature allows you to return a partially completed page to the browser where placeholders like spinning loaders (using Suspense) occupy the space where a component is still awaiting some data to be returned. Once the data has arrived, RSC will replace the placeholder with the relevant component which is suitably populated with the new data.
Object Relation Mapping (ORM) tools are libraries that simplify access to databases. They allow developers to query and manipulate data from a database using an object-oriented paradigm, without having to write a SQL/NoSQL query. One such example is Prisma.
This means that instead of writing raw SQL like this:
SELECT * FROM users WHERE email = 'hsimpson@springfield.com';
We can do the following:
await prisma.user
.find({
where: { email: 'hsimpson@springfield.com' }
})
While this is quite a simplistic example, it suggests the benefits of significantly more complex examples involving complicated object graphs with associations across multiple tables.
Prisma offers a host of other benefits such as:
With its many benefits, a growing user base, and a dedicated development team constantly working to enhance the tool, Prisma remains a highly sought-after solution for developers utilizing modern frameworks such as Next.js, Remix, and others.
It may appear unusual to consider this a significant advancement in the realm of UI. However, Prisma's ability to simplify database access, coupled with the consolidation of server and UI logic in frameworks like Next.js and Remix, makes it easier for front-end developers to delve into full-stack development. Thanks to tools like Prisma, front-end developers can avoid constructing complicated SQL/NoSQL queries and instead utilize a user-friendly interface to achieve the same functionalities.
It has been a common practice for some time to use loading spinners while waiting for data to be loaded in a component or page. However, this is not always seen as a positive user experience, as spinners do not provide any information on progress. As a result, users don't know how much longer they have to wait, which can create the perception that the wait is longer than it actually is. This can lead to disappointment, such as waiting for a page to load and not having the needed information. This frustration is particularly evident when multiple spinners are displayed on a page like a dashboard, which can make the user wait a significant amount of time before the entire page is available.
An alternative is to use skeleton loaders, which have been found in one study to be perceived as faster than loading spinners. This is an approach adopted by big organisations such as YouTube, Medium & Facebook. However, like loading spinners, skeleton loaders also do not provide any indication of progress and can lead to disappointment.
Avoiding the shortcomings of loading spinners and skeleton loaders is possible by using approaches such as:
These alternatives aim to reduce the waiting time and provide more information to the user.
Stale-While-Revalidate is a strategy to show stale data from a cache whilst triggering a re-fetch for new data (revalidate), eventually replacing the cached value and updating the results rendered on the page. An example of this would be showing a list of posts on a page. If the user navigates away from the page and then returns, we show the same data as before from the cache, whilst triggering a request to fetch potentially new data. Upon receiving this data, the cache is updated and the new list of Posts is rendered to the screen. The effectiveness of this approach requires a good balance between Time To First Byte (we show stale data for a shorter period if the request is quick) and how often the data changes on the Server.
Optimistic Update is an approach that treats mutation requests such as PUT/POST as immediately successful and updates the local state before receiving a response from the server. This creates a fast and responsive user experience. If the mutation fails on the server, the local state can be rolled back and a message displayed to the user. Implementing Optimistic Updates requires careful design to ensure consistency between the local state and the server.
Incidentally, React Query and SWR libraries provide both capabilities, resulting in a UI that is both fast and reactive.
A Design System consists of a library of reusable UI components which conform to a set of design patterns and standards enabling developers to build consistent and accessible applications quickly. In addition to serving as a common language between different team members such as engineers, designers and product owners, Design Systems can offer the following benefits:
Design systems are increasingly being adopted by small startups to large companies, all of whom seek to profit from the benefits on offer. Companies can incorporate a Design System in one of the following ways:
Many large companies such as Airbnb, Uber, and IBM have developed their own Design Systems to help develop their family of digital products. Whilst this can be costly, it enables greater flexibility that may not be possible from Open Source systems.
At Griffiths-Waite, we have implemented our own Design System to deliver a suite of applications for a Key customer. It's based upon the Atomic Design methodology, which is focused on decomposing an application down to its constituent building blocks ranging from simple buttons to advanced tables. Consequently, we could deliver a number of different products using the same UI library and standards.
One of these was a pure React application and the other was a hybrid Oracle JET / React application. The Design System was developed in parallel to implementing the first app and retro-fitted on the second. The consensus on both product teams was favourable toward the Design System with the significant gains being:
The key takeaway was that Design Systems provide an efficient and optimised approach toward application development, especially within an enterprise environment.
React remains at the forefront of the UI market as it has been for several years. With its ongoing development, the technologies surrounding it have progressed, bringing about advancements such as:
It will be interesting to review this in a couple of years' time to see what further developments have occurred.
Enter your email below, and we'll notify you when we publish a new blog or Thought Leadership article.