React Component Management

Components have taken over front-end development. Chances are if you’re developing a web application UI layer, you have integrated some kind of component via a framework like React or libraries such as Bootstrap. In this episode of SE Daily with Max Stoiber, we’ll explore the history of components, modern component development with React, and look to the future through examples and comparisons across frameworks and paradigms.

What is a component?

A component is the most basic encapsulation of a user interface. It is a UI-layer abstraction that makes objects easier to understand. Rather than thinking of HTML as a series of tags with endless classes and IDs, components allow you to write what feels like XML to abstract away the HTML jargon with tags that are more relevant to the applications you want to build.

History of UI development

We have had components since the dawn of web development, though we’ve referred to them by different names over the years. Many server-side languages have provided components (often called templates) via includes in PHP or partials in Ruby.

On the front-end, libraries such as jQuery, Dojo, and Backbone later came along and provided their own templating plugins but were much bigger than what you see today. In fact, these design decisions inspired the modern wave of component development to shift from larger encapsulations to really small ones in a bottom-up approach.

Best practices around components

Getting started with components is easy. Maintaining components for a production-ready application is a bit more nuanced. Here are a few simple rules to keep in mind when developing components:

  • Keep things consistent and eliminate redundancy. Leveraging components like a design system prevents endless variants through sensible restriction.
  • Aim for extensibility and flexibility. By having a design system in place, your simple base components can serve as a backbone for more complex UI interactions.
  • Think in components for both composition and styling. Components are not just about visual elements. As we will see in the next section, we can turn virtually anything on the front-end into a component to keep abstractions simple and easy to manage.

Containers vs components

As we mentioned earlier, not all components have a visual element to them. We can clarify that distinction with something called containers. While components focus on rendering and styling, containers tend to focus on data fetching, manipulation, and logic.

Are you adding a grid to your page? That’s a component. Querying GraphQL via Apollo? That’s a container.

How to refactor with components

If I’ve sold you on the benefits of a component-based architecture, how do we begin to integrate all of these practices into our existing front-end applications?

For containers

As I mentioned earlier, GraphQL, and more specifically, Apollo, are excellent ways of thinking about containers. To start using these, it will require some buy-in from your backend API developers. Given that most legacy architectures run on a RESTful pattern, it may take some time to port this over to the GraphQL paradigm. Once you have the server set up you can integrate this with a GraphQL client such as Relay or Apollo (we’ll get more into these later).

For components

There are two strategies for beginning to integrate components on your front-end application. The first is with styling-only components. Examples include buttons, grid, and typography. If you’ve ever used Zurb Foundation or Bootstrap, then you can create your own variants that are suited to your application’s brand and styling.

The next refactoring technique centers on writing CSS in JS. Tools like emotion and Max’s styled-components make it easy to write CSS directly in your JavaScript files without having to manage all of the necessary piping that comes along with managing your HTML, CSS, and JavaScript separately.

Shortcomings of CSS and styling

One issue with CSS in relation to component-based architectures is that CSS wasn’t invented for dynamic components, but for long-form, static documents. Since HTML’s origin was in structured, static documents, CSS fit very nicely into that paradigm. In today’s world, few if any sites (outside of statically-generated websites) operate without some sort of dynamic JavaScript.

One example of CSS making modern web development more difficult is with naming. Naming has always been a hard problem, but it is especially difficult with CSS given the global scope of class names for your application. If you have two libraries and they both use a class .grid,  how do you override that or make sure it doesn’t break what is part of your imported library?

Instead, it is advised to remove the idea of classes and class names altogether. Computers are better at keeping track of these kinds of things that

This is a lead text and needs your attention.
This is a lead text and needs your attention.
we are, so let them handle it and we can focus on the important parts, such as applying styles and focusing on our UI fragments and all of their various flavors and variants.

Solution: styled components

As we mentioned earlier, one solution to this problem with CSS includes a solution developed by Stoiber aptly called Styled components. These components are just simple React components that automatically generate unique class names injected via a style tag.

Sounds like inlined styles…aren’t those bad?

One common question heard over and over again is whether or not this solution injects inline styles into your CSS. When you encapsulate styles into a component, one could easily imagine some HTML rendered along with a style attribute to apply those styles.

Stoiber’s solution is able to apply styles without breaking the cascading part of CSS. Instead over overriding all styles via the attribute, the CSS is being injected via a unique class name into a <style> tag. In the end, you still have just plain old CSS being generated in your HTML file and you don’t have to worry about how you name your CSS classes (or that they even have to exist at all). Styled Components abstracts all of that away so you can focus on making your UIs look great.

Architecting components by example: Spectrum

Stoiber took all of these best practices about components and has applied them to his project Spectrum. Spectrum is like StackOverflow or Quora but with more open-ended discussions in online communities, like a blend of chat and a forum. Long form discussion works because it’s not ephemeral like Slack, but more real-time than a forum like Discourse. The key is that threads are still searchable and accessible long after the discussion has lost steam. What does a complex, real-time application like this look under the hood?

  • Database: RethinkDB. This database is great for real-time development because you can listen for changes via Changefeeds (essential for a chat app). And it integrates well with Node and the GraphQL server (via GraphQL subscriptions).
  • Backend: Node. Since all of Spectrum’s developers know JavaScript, this was the obvious choice for their backend server-side technology.
  • API: GraphQL. The GraphQL server was an obvious choice based on Stoiber’s interest in GraphQL over REST.
  • Jobs/Queues: Redis. Redis is a battle-tested queuing service and is a great choice for managing asynchronous data processing.
  • Client-side: React, Apollo, Styled-Components, Redux. It’s no surprise given this episode centers around React that Stoiber chose this stack for the front-end of the Spectrum application.

GraphQL on the client-side with Apollo

Apollo was covered more in-depth in our NYTimes article, but as a GraphQL client for Spectrum Stoiber says this decision has worked out really well for them, too.

Apollo was originally developed by the team who created Meteor. Originally, their goal was to create a highly-opinionated, integrated JavaScript framework similar to Ruby on Rails. Even though it gained traction, it never fully materialized into a production-ready application because trends in front-end development favored modularly over the monolith (hence the success of React). Luckily, the Meteor team pivoted to owning the GraphQL stack and renamed to Apollo. Apollo is now a primary contender for GraphQL clients alongside Relay.

Testing with components

One issue that Stoiber admits is the Spectrum team hasn’t solidified any best practices with testing components. On an individual level it doesn’t make sense because unit tests for components are often excessive, especially if they contain no logic and only display styles.

Even in end-to-end (E2E) testing it can be cumbersome. E2E is great for views for the happy path, a term used to describe the basic, valid interaction you aim to have with a page. An example of an authentication happy path would be clicking the login button on your homepage, successfully filling out your email and password, and clicking the submit button to redirect you to your dashboard.

Stoiber also admits this lack of testing does introduce bugs, but when you are moving as quickly as Spectrum is, it’s hard to take the time to be super thorough. Design systems and stateless components do restrict you which is both a good thing (i.e. no mess and consistency) and a bad thing (i.e. UI limitation and rigidity). This also means, as it relates to testing, that you can limit the things you need to test.

Comparing components across ecosystem

If components are central to the React architecture, and React has been so successful for Spectrum and front-end development in general, how does this paradigm compare to the other major ecosystems like Angular and Vue? Stoiber provides some insights when evaluating the three major frameworks:

Vue

VueJS works nicely and is similar to React. Stoiber says he wouldn’t use it in production because it’s not as mature as React or Angular. Because of that lack of maturity, you can’t get as many off-the-shelf components in Vue as you can with React. You’ll find tens of video player components in React, but you may have to roll out your own in Vue.

Instead, their focus has been on onboarding and a fast learning curve which makes it the up-and-coming player to look out for (in fact, since the airing of this episode, Vue now has more stars on Github than React does).

React

Regardless of bias for React, it has become the standard JavaScript development framework. With big industry support via Facebook, it has become one of the largest open source projects to date. Hundreds of off-the-shelf components and plugins make it extremely robust, and therefore make you exceptionally productive. By doing a very limited set of things out-of-the-box, React gives you the flexibility to plug in your own stack and architect your app the way you see fit, rather than the other way around.

Angular

Angular, on the other hand, does enforce a highly opinionated architecture. Angular’s directives are what they call components.  They moved towards a component-based architecture with versions 2 and beyond, but all of the other libraries such as templating, filters, and models offer a different perspective from the plug-and-play nature of React. Because of this monolithic enforcement that bucks the trend of modern front-end development, Stoiber notes he isn’t seeing new projects using Angular nearly as much as they used to be.

Implications for WebAssembly

JavaScript can be annoying because it’s so flexible. One can write JavaScript in an object-oriented or functional paradigm, and the language itself was written quite hastily in its early days.

Instead, it would be great to move to a world where we can interact with the browser directly in whatever language we are comfortable writing. In this way, native development, such as with C++ or Rust, would be great to cut out the JavaScript middleman. WebAssembly is the answer to this problem, but it is still in its early days, too.

One major limitation of WebAssembly is it’s lack of a DOM API. This is a serious limitation right now, which means you won’t see React ports in Rust or C++ anytime soon. However, we are already seeing other ports like ReactNative for mobile and React360 for AR/VR, so it is only a matter of time before we start to see React available on a host of other, more mature languages.

Adam Conrad

Boston, MA

Adam is a Boston-based designer, developer, UX consultant at Anon Consulting. He runs a UI and UX engineering publication over at UserInterfacing.

Software Daily

Software Daily

 
Subscribe to Software Daily, a curated newsletter featuring the best and newest from the software engineering community.