paint-brush
Checklist for Writing Highly Reusable Components in React and Vueby@michaelnthiessen
8,371 reads
8,371 reads

Checklist for Writing Highly Reusable Components in React and Vue

by Michael ThiessenAugust 8th, 2018
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

There are so many best practices and advanced<em> </em>patterns — the problem is keeping track of them and keeping them in mind as you develop new components.

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Checklist for Writing Highly Reusable Components in React and Vue
Michael Thiessen HackerNoon profile picture

Photo by Kris Guico on Unsplash

There are so many best practices and advanced patterns — the problem is keeping track of them and keeping them in mind as you develop new components.

I wrote this checklist to help myself remember all of the things I need to be thinking about as I go through building highly reusable components.

This checklist applies equally to both Vue and React.

Really, it doesn’t matter which framework you use, since the principles of component composition are exactly the same. And the general process for designing a component doesn’t change either.

Condensed checklist at the end of the post.

Avoid speculative generality

This one sounds pretty obvious, but I find myself forgetting this all the time.

You need to fully understand your use case, and only implement that. If you just dive into code without thinking first, you’ll end up writing in a bunch of features that will never be used. That’s a colossal waste of your precious time.

When writing a component that is supposed to be reused across many different use cases, the temptation to provide more and more abstraction is easier to justify.

However, if you write the component well, it should be fairly easy to come back later and add in new use cases you couldn’t anticipate.

This is where 80/20 thinking comes in handy. A few of the features you implement will be responsible for handling most of the use cases. Focus on those.

I’ll leave you with one last tweet about API design:

Simplify the API

Now that we’ve stopped to think, let’s simplify our API as much as possible.

You’re also trying to find the sweet spot between simplicity and flexibility. As Ken Wheeler said in A Bitter Guide to Open Source:

You want to find the perfect balance of working out of the box, and configuring as necessary. On top of that, you want to keep things clear, explicit and approachable. Don’t be too clever or you will piss everyone off.

Too simple and it doesn’t cover enough use cases to be helpful. Too flexible and it becomes too difficult to understand how to do anything.

Just take a look at how many options this jQuery Datepicker has. It’s terrifying!

This is where more advanced composition patterns really come in handy.

Typically you’re making trade offs between simplicity and flexibility. But techniques like render props and compound components allow you to achieve more flexibility while reducing complexity.

Research prior art

We have a pretty good idea of what we we’re building now, but first we need to see what else is out there.

There are a few reasons for this:

First, we can get great ideas for our implementation.

If we look at mature open source projects, they will be more or less feature complete. This lets us double-check our assumptions about what we might need to build out.

We can also see how the API was built, what abstractions were used, and possibly even some implementation details we wouldn’t have considered.

Second, we can potentially save ourselves some work.

There’s a good chance we’ll find something that we can use to speed up development. We may even find something that ticks all our needs, and end up short-circuiting this whole process.

In his Advanced React.js course, Ryan Florence mentions that he likes to check out jQuery plugins. They’ve stood the test of time, and likely have all the features that you’d ever consider putting in a UI element.

A great place to start is in the Awesome repos:

Break up components into bite-sized pieces

Compositional frameworks use components as their main technique of abstraction (vs. objects in OO or functions in functional programming).

If you shove everything into one or two giant components, you aren’t taking advantage of this at all!

Smaller components are better:

  • Better abstraction makes your code cleaner, easier to understand, and easier to maintain
  • Encourages reusability of the code
  • Necessary in order to use more advanced fancy-pants composition techniques

There are a couple main ways to think about splitting up components:

Isolating behaviour from presentation

You have state and logic in one component, with a separate component responsible for rendering. We would typically do this through render props and stateless functional components.

Levels of abstraction

It’s often a good idea to keep the level of abstraction consistent within a component. Either the component would deal with native DOM elements, like div, p, span, or it would deal with framework components.

Just be careful, because you don’t want to go overboard and create too many components! Kent C. Dodds has a great article on how to know when things should be split up.

Use powerful composition patterns — only where needed

Render props, provider pattern, higher order components. These patterns are seductive and fun to use.

But they are not always the right tool for the job. Knowing when to use each one to it’s maximum effect is important. Otherwise you may use the wrong tool for the job and dig yourself into a hole.

If you want to learn more about these, I highly suggest checking out Kent C. Dodd’s article on advanced patterns in React:

Compound components

Break up parts of your component into smaller bits that can be recombined in different ways.

For example, take your Table component and break it down into TableHeader, TableBody, and TableFooter components. Most people will be fine to use the regular Table, but now someone can build their own table and build a custom header for it without too much trouble.

Higher order components

Take a component and wrap it up inside another component to add functionality to it. This concept evolved from the object-oriented idea of mixins, but has largely replaced it (although Vue still has supports mixins).

When React first came on the scene, mixins gave developers an escape hatch, allowing them to go back to something familiar from the object-oriented world.

After awhile we figured out that composition is far better than inheritance, so higher order components became the norm.

Render props and renderless components

Now we’re seeing another shift. This time away from higher order components, and towards what are called render props (or function as children).

Render props let us delegate rendering to the parent component, giving us even cleaner separation between behaviour and presentation. If you combine this pattern with the prop getters and setters pattern, you can build incredibly flexible and expressive components with very few lines of code.

Controlled and uncontrolled props

Does the component control the state, or does it’s parent control the state? That is the difference between an uncontrolled and a controlled prop.

Generally, uncontrolled props are used since they allow us to encapsulate complexity and state within the component. However, if you want more flexibility — which we need when writing a highly reusable component — you can allow a prop to be controlled by the parent.

State reducer

This is a pattern I learned from Kent C. Dodds in his project Downshift (more explanation here).

If you’re going to expose a prop to be controlled, why not expose the entire state reducer? Then you can have extremely fine-grained control over the behaviour of the component — but you don’t have to re-write any logic.

Brilliant.

Provider pattern

If you’ve used Redux or VueX or something similar, you probably know this pattern.

Instead of passing props around all day long, and passing them down through many many levels of components, you simply “inject” them where they need to be.

In React this can be done using context, or provide and inject in Vue.

Accessibility is not an afterthought

I’m not very good at accessibility yet.

It’s something I’ve been getting better at recently though, because I believe it’s incredibly important to making the web a better place.

Since I’m not an a11y expert, I’ll instead get you to read this article Addy Osmani wrote on developing accessible web components. You can also check out the great resources of The A11Y Project.


Accessible UI Components For The Web_To be accessible, UI components need to work across multiple devices with varying screen-sizes and different kinds of…_medium.com

Make it easy to style

How easy is it for consumers to style your component the way they need?

The intention is that your component will be used all over the place. In all sorts of wild and various contexts. It will be used in ways you could never have imagined even in your weirdest dreams.

You need to make sure that other devs can easily style and change the layout of your component without resorting to ugly CSS overrides.

Renderless components make this super simple. You can just delegate all rendering to whoever is using your component.

However, in many cases it’s useful to render something by default. A good approach here is to use BEM in your component and provide CSS classes that can be easily overriden.

But CSS isn’t Turing complete!

Alternatively, you can take the cool-kid approach and use CSS-in-JS (it’s not for everyone).

When this idea started out, most libraries were implemented using inline styles. This caused some performance issues and had some other issues as well.

Nowadays, most libraries work by dynamically attaching stylesheets to the DOM, and the biggest issues have been resolved. I haven’t had a chance to dive into these in awhile, but it’s on my list!

There’s tons of libraries, talks, and articles out there about this if you want to learn more, but here is a good place to start for React, and here for Vue.

Do you even test, bro?

You don’t want tons of people using your beautiful new component, only to have it flake out on edge cases. Or heaven forbid you add a slick new feature — but it breaks everything else.

When you’re building a reusable component like this you probably won’t do any integration or end-to-end testing. You’ll be writing unit tests that focus on testing tricky logic and making sure the component is rendering properly.

Here are a few great articles on testing React and Vue components if you need to get started:


Fullstack React: Introduction to Testing_Test suites are an upfront investment that pay dividends over the lifetime of a system. Today we'll introduce the topic…_www.fullstackreact.com


Unit Testing Vue.js Components with the Official Vue Testing Tools and Jest | Alex Jover Morales_Vue.js has become the framework of the year. It's very flexible, performant and easy to learn that lead to a massive…_alexjoverm.github.io

Documentation — It’s what makes all the difference

“I’ll write the docs later”, you think to yourself as you push the last beautiful crafted commit to Github. “I mean, even if I don’t get to it no one will really care.”

After all, you’re a professional at writing in Javascript, not one of these “natural” languages that humans speak.

But great documentation is what turns a good component into a great component.

You know the feeling when you’re trying to figure out how to get a library to do something, or you get confused about React’s (or Vue’s) lifecycle methods. If you can’t find the answer quickly, it’s super frustrating.

Sometimes you’ll even get rid of the library because you can’t figure out how to get it to work!

Don’t let your shiny, brand new component to go to waste because of a lack of good documentation.

Condensed Checklist

Now that we’ve gone through all of that, here is the easy-to-reference version:

Avoid speculative generality

Simplify the API

Research prior art

Break up components into bite-sized pieces

  • Separate state + behaviour from presentation
  • Split up by level of abstraction

Use powerful composition patterns — only where needed

  • Compound components
  • Higher order components
  • Render props and renderless components
  • Controlled/Uncontrolled props
  • State reducer
  • Provider pattern

Accessibility is not an afterthought

Make it easy to style

Do you even test, bro?

Documentation — It’s what makes all the difference

Check out my articles as soon as they come out at michaelnthiessen.com! I re-post them here a few weeks later.