The 3 essential rules of really-reusable JavaScript components

Written by antoine.stollsteiner | Published 2018/02/26
Tech Story Tags: javascript | components | react-components | react | vuejs

TLDRvia the TL;DR App

How can I reuse this supposedly reusable component in the page I’m building?

So you’re using a components-based framework such as React JS, Vue JS, or the latest Angular? React popularized the idea of components a few years ago as a way to reuse code and build web apps more efficiently.

“That’s great in theory, but in my experience these fancy “reusable” things are never reused”, said my skeptical 43 year-old coworker, as I introduced the team to VueJS.

As the project went on, it turned out he was mostly right. The emergence of this new paradigm of component-based interfaces has left many questions unanswered:

How do you define the scope of a component? How do you decide what should be included in one component, and what should be left to a separate component ?Where do you put the styles?At what point is it better to have 2 separate, but more simple components, rather than one generic component that’s overly complicated ?

TL, DR, the 3 essential rules of reusable components :- make as few components as possible- components should be “just generic enough”, and ideally, should be extracted organically from app pages as you build them- two simple components are better than one generic, complicated component

Note : most examples in this article are using React, but the general ideas are relevant to any JS component based framework, such as Vue or Angular.

Make as few components as possible

The problem: Too many layers in the component tree.

For my first React app, I made the mistake of dividing simple functionality in too many components. I almost made a component for every “div” layer… This means a lot of time was wasted passing props down the components’ tree. It is tedious and if you forget one prop in one layer, the app breaks. Whenever you want to change the signature of a component in the chain, or whenever a prop type changes, you need to make the change at every layer.There is a negative impact on development speed, but also a negative impact on performance, when you divide your app in more components than absolutely necessary : more function calls, more files to resolve and bundle (see The Cost of Small Modules).

The solution: only divide a page or a block in multiple components when absolutely necessary.

Looking at other people’s React code on GitHub helped me realize what I was doing wrong.

Example: a menu with a list of links.

In the past I would spontaneously make two components : a MenuGroup component and a MenuItem component.

This will work. But, if the menuLinks are not dynamic, it is better to avoid making a MenuItem component altogether, and describe the whole menu in a single Menu component, with hardcoded data:

To reduce your component count, avoid making components that only add styles. Instead of having a BlueButton component, it is better to just use an html tag “button” and add a “.blue” class to it.

In general, if you want a component to be reusable, include as little styling to it as possible. I put reusable styles in a different folder then I import them in a component when needed.As a general rule, only make a separate component if there is custom logic. I would not make a BlueButton, but could make an AddItemToCartButton.

Components should be “just generic enough”

The problem: Simple or Generic ?

There is a trade-off between a straightforward component that only covers a few use cases, and a generic component that can be used in many situations but has a lot of props and is more complicated.

The solution: Only use external component libraries if you really have to.

So much for code reuse or reinventing the wheel? For me, the purpose of libraries such as React-bootstrap is not to be used as a drop-in in your project. I just look at their code to see how they solved some problem that I am facing when building my own custom component. For example, how to make an infinite scroll component, or a drag & drop to upload a file. I will copy the core idea, which is often no more than 10 lines of code, then build my own component around it, removing a lot of bloat and unneeded complexity.

The problem with generic components from external libraries is that they have to cover many use cases that are irrelevant to your project, making your codebase bloated and harder to read. They often include styling which makes it harder to insert them in your page.

From experience, it often takes longer to understand how the API of the component in an external library works, including its inevitable quirks, than it takes to make your own component.

Again, try to include as little styling as possible in a component, if you want it to be generic.

Use slots instead of props

Whenever possible, use slots instead of props. In Vue JS this means using named slots. In React, where you only have a default slot,it is recommended to use higher-order components (ie decorators) to add functionality, instead of props.

Example : Instead of receiving the title as a prop, it is better to put it in a slot:

This will make the component much more readable in the long run, and makes it way easier to access styles of subcomponents.

When making a component reusable, connect it directly to the global state.

If the component is supposed to be used in different contexts, only put in props the data that is inherited from the direct parent component. Whenever possible, get the data directly from the global state using “react-redux” connect method. This way, if some data is only needed in this component, you won’t need to pass it down the whole component tree.

Example: a block displaying info on the current user can get the data from the global state instead of receiving it from its parent.

Two simple components are better than one generic, complicated component

The problem: it is often easier to duplicate then hack, than to reuse

More often than not, it was faster for a teammate to duplicate the component file, hack it to fit the page he was working on, and save the file under a different name, than use the component “as-is”. A component has only proved its reusability once you see other team members using it, and if they really save time using that component. If you or your coworker is spending time wondering, “how can I make this component fit into that page ?”, you’re doing it wrong.

The top-down approach consists of building (or downloading) the library of components first, and then trying to fit it in the page that you are supposed to build.

This component won’t fit in that page.

The solution: Use a bottom-up approach instead. First build the page, and then extract components organically from your app.

Code reuse is nice, but development speed is more important. It’s ok to start by duplicating an existing component. The two components can sometimes be merged later on.

Here is a simple development workflow that emphasizes the 3 rules outlined above:

  1. Start by building the first page in a single component
  2. Build the second page also in a single component
  3. If, and only if, there are common components between the two pages, make them generic and extract them to a separate folder.

In this way, a library of custom components will emerge over time, that are tailored to your app.

If you found this article helpful, be sure to have a look at React Without Webpack: Faster Developer Workflow , which explains how to avoid the build step during development.


Published by HackerNoon on 2018/02/26