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?
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).
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.
Shortcomings of CSS and styling
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
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).
- 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.
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:
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).
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
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.