How to Maximize Reusability for Your React Components
Tags: JavaScript, Programming, Vuejs, Nodejs, React

The Component

Let’s build a List component and try to expand its capabilities from there.

Pretend that we’re building a page where users are redirected after they register to become part of a community of medical professionals. The page should show lists of groups that doctors can create that newly registered doctors can view. Each list should show some type of title, description, the creator of the group, an image that represents their group, and some basic essential information like dates.

We can just create a simple List component that represents a group like this:

Then we can easily just render it and call it a day:

Obviously the component isn’t reusable, so we can solve that issue by providing some basic reusability through props by children:

But that doesn’t make much sense, because the List component isn't even a list component anymore nor should it even be named a list because it's just now a component that returns a div element. We might as well just have moved the code right into the App component.

But that's bad because now we have the component hardcoded into App . This might have been okay if we're sure that the list is for one-time use. But we know there will be multiple uses because we're using it to render different medical groups on our web page.

So we can refactor List to provide narrower props for its list elements:

This looks a little better, and now we can re-use the List like so:

There’s not much here to the styles, but here they are to avoid confusion:

A small app constrained to just this web page can probably just get by with this simple component. But what if we were dealing with potentially large datasets, where the list needs to render hundreds of rows? We would end up with the page attempting to display all of them, which can introduce issues like crashing, lag, elements being out of place or overlapping, etc.

This isn’t a great user experience, so we can provide a way to expand the list when the number of members hits a certain count:

It seems like we got a pretty good reusable component for rendering lists of groups now.

We can absolutely do better. We don’t really have to use this component specifically for groups of an organization.

What if we can use it for other purposes? Providing a prop for the label (which in our case is Group ) can logically make that happen:

You can then use it for other purposes:

When thinking about how to make React components more reusable, a simple but powerful approach is to re-think how your prop variables are named. Most of the time, a simple rename can make a huge difference.

In our App component, we can also provide a custom prop for the Members part:

Now if we look at our component and only provide the members prop, let's look at what we get:

I don’t know about you, but what I see here is that the list can actually be used for anything!

We can reuse the same component to represent patents waiting in line for their next appointment:

Or we can use it on bidding auctions:

Do not underestimate the power of naming variables. A simple naming fix can become a game-changer.

Lets go back to the code. We did pretty well on expanding its reusability. But in my perspective we can actually do a lot more.

Now that we know our List component can be compatible to be reused for totally unrelated reasons, we can decide to break up pieces of the component into subcomponents to support different use cases, like so:

Functionally it works the same way, but now we split different elements into list subcomponents.

This provides some neat benefits:

We can now test each component separately.

It becomes more scalable (maintenance, code size).

It becomes more readable, even when code becomes larger.

We can optimize each component with memoization using techniques like React.memo .

Notice that the majority of the implementation details stayed, the same but it’s now more reusable.

You might have noticed that the collapsed state was moved into ListComponent . We can easily make the ListComponent reusable by moving the state control back to the parent through props:

Knowing that ListComponent became more reusable by providing the collapse state management through props, we can do the same for List so that developers that use our component have the power to control it:

We’re starting to see a pattern emerge here. It seems like props has a lot to do with reusability — and that's exactly right!

In practice, it’s not uncommon that developers want to override an implementation of a subcomponent to provide their own component. We can make our List component to allow for that by providing an override from props as well:

This is a very common but powerful pattern used in many React libraries. In the midst of reusability, it’s very important to always have default implementations in place. For example, if a developer wants to override the ListHeader , they can provide their own implementation by passing in renderHeader . Otherwise, it will default to rendering the original ListHeader . This is to keep the list component staying functionally the same, and unbreakable.

But even when you provide default implementations if an override isn’t being used, it’s also good to provide a way to remove or hide something in the component as well.

For example, if we want to provide a way for a developer to not render any header element at all, it’s a useful tactic to provide a switch for that through props. We don’t want to pollute the namespace in props, so we can re-use the header prop. That way, if they pass in null , it can just not render the list header at all:

We can go further still with our reusable List component. We aren't constrained to providing overrides for the ListHeader and ListComponent . We can also provide a way for them to override the Root component like so:

Remember that when we provide customizable options like these, we always default to a default implementation, just as we defaulted to it to use the original ListRoot component.

Now the parent can easily provide their own fashionable container component that renders the List as its children:

Sometimes developers also want to provide their own list rows. Using the same concepts we went over throughout this article, we can make that happen. First, let’s abstract out the li elements into their own ListItem component:

Then change the List to provide a customizable renderer to override the default ListItem :

And slightly modify the ListComponent to support that customization: