Building Reusable React Components

How to build reusable components in React along with some of the best practices to follow

Normally in vanilla JavaScript, when you want to re-use some code, you write it as a function. In React however, you write your code as a component.

In this post, I will show how we can create custom re-usable React components, and share them between apps. I will also go through some of the best practices that I think can help build better reusable React components.


Project Setup

First, I will create a new React Project using the create-react-app command:

create-react-app my-app

Building a Simple, Reusable React Component

Once the project is created. Go to the App.js file and change the existing code with this snippet:

Here, there is a <div> element that has some text inside it. If I want to replicate it, I will have to write the same div element again. What we can instead do is extract the div element inside a variable, and write that element directly in my app’s JSX.

If you run yarn start command, you will see that the app renders the text the same way in both cases.

What if I want to render some other kind of text? Or if I want to render two different texts?

To do so, I am going to make some changes to the helloWorld variable.

First, I have renamed the variable as message. I am then passing props as an argument to this variable. Note that I am using ES6 arrow function to do this.

props is an object that has a msg property in it. Inside the App component, I am replacing the {helloWorld} with {message}. Inside this message variable, I am defining the msg prop with some text.

I’ve now created a simple, re-usable React component. I have taken some JSX, wrapped it inside a function, and made a function call to render some text.

But function calls don’t really compose as well as JSX does. It would be better to turn these function calls into JSX. So let’s start out with React.createElement and see how we can convert into JSX. A great thing about React.createElement is that can take a string and a function to indicate what element we want to render.

It will pass the props to the function, and that function presumably will some more elements. Here, the message function is rendering a <div>.

But this looks way too complicated. Let’s simplify things like this:

Here, I am changing my message function to Message, changing the function into a component. By doing so, I can use it as a self-closing element inside the App component as shown in the above code snippet.

If I change the msg prop to children prop, React will still render the exact same thing. I can even put one Message element inside another Message element.

class App extends Component {
render() {
return (
<Message>
Hello World
<Message>Reusable Components</Message>
</Message>
);
}
}

So, to create a re-usable component in React, all you need to do is create a function that has a capital letter as its first character. This function should receive props as an argument and you can use these props in whatever it is that you want your re-usable component to return.


Reusable Components — Best Practices

To create better User Interfaces in React, it is always suggested that you break down the common design elements such as buttons, forms, etc., into reusable components with well-defined interfaces.

This way, the next time you want to build a UI, you will have to write much less code. This results in a faster developement time, lesser bugs, and even lesser bytes down the wire.

It is quite easy to break down your app into reusable components. The real question is, which parts of your app should you make reusable?

I have created an app that consists of three main components:

The Code component here contains the main functionality of the app. This will not be used in any other app. The Header and the Footer on the other hand, can be used in other apps.

One way to transition your component from one app to another is to just copy and paste it and then make some changes to it as per the particular app’s needs. But this is neither an easy nor a practical method.

Let’s take a look at some of the best practises that will help you build reusable components.

#1. Use strong wrapper elements

React’s render requires you to wrap all the elements inside it into a main parent element. The question is, what kind of element should I use? Should I use a <p>, a <div>, or something else?

Whatever element you decide to use as wrapper, make sure that it is a strong one. For example, a <p> tag can be defined as a weak element since since will throw you an error if you try to place a <div> tag inside it.

A <div> tag on the other hand, does not throw any kind of error. You can place as many elements as you want inside it, and they can be of any kind.

If you are using React 16, you can use React.Fragment as a wrapper as well!

#2. Declare PropTypes

PropTypes are especially useful in building reusable components. It is always advised that you define PropTypes for all your components, reusable or otherwise.

Rajat.propTypes = {
movie: PropTypes.string.isRequired,
pizza: PropTypes.string.isRequired,
};

PropTypes are especially useful in clarifying the component’s API. They will define your props’ data types and whether your App absolutely requires it or not.

When the user enters invalid data type or if there is a missing propTypes, React generates a warning informing what you need to do. This will help speed development, and avoid time consuming debugging sessions.

You can even specify the expected shape of any objects that you pass via props.

Rajat.propTypes = {
user: PropTypes.shape({
name: PropTypes.string,
age: PropTypes.number
}),
}

If you are not in the habit of defining PropTypes, you can enforce this using linting.

#3. Avoid Hard Coded…

The thing about reusable components is that they will be used in multiple apps. And often they are used multiple times in the same app.

Therefore, it is better to avoid hard code in our app. By this, I mean to say that we should keep the HTML IDs in our reusable components.

Why should the HTML IDs be unique? Because:

  1. HTML IDs may conflict with other things on the page where your app is using a reusable component.
  2. Putting a hard-coded or static HTML ID in a reusable component can potentially cause errors in your app. React may throw you an error saying there are invalid duplicate IDs if your app is using multiple instances of the component on the same page.

To avoid these things, I would suggest you to accept an ID through a prop.

Rajat.propTypes = {
OneID: PropTypes.string.required
}

#4. Declare Logical Defaults

Well thought defaults can make your reusable components more approachable and reduce the amount of work to get set up.

Good defaults will also save your app’s user from typing as they will not have to populate as many props.

Defaults will help assure useful app behavior by conveying a mainstream approach without any customization.

Default props will help you convey to the users how the components work by showing a common use case that is populated with realistic data.

Counter.defaultProps = {initialCount: 0};

Here, I have a class named Counter. I am specifying that the Counter class has a prop named initialCount whose default value is 0. This default value is used by the app when no other value is provided to it. This is declared below the Counter class.

You can also declare the defaultProps inside the class using static like this:

class Counter extends React.Component {
static defaultProps = {initialCount: 0};
render() {
return ()
}
}

If you are writing a stateless functional component instead of a class, you can declare the defaultProps using default parameters.

const Counter = ({initialCount = 0}) => {}

Here, I am destructuring the props and the declare the initialCount to be equal to 0 if a value is not passed in on props.

#5. Make your app accessible

Keep in mind that people may not click on your inputs. Instead, they may only interact with your app through some other input device, such as a keyboard. Therefore, it is important that your app responds to common keyboard inputs like arrow keys.

Keyboard users often use Tab to move between inputs. So make sure that your app honours the tab indexes and that the tab indexes are set in a logical order.

React comes with elements like text and button. Use these instead of div and span wherever possible. Elements like text and button have a proper behavior in-built for event handling, focus, and keyboard inputs.

Also, investigate Accessible Rich Internet Application(ARIA) and Role attributes to enhances your component’s accessibility. ARIA defines a way to make web content and web applications more accessible.

#6. Consider Configuration Objects

If your reusable component has or is likely to have a large number of props, then accept a configuration object on your props. A configuration objects places a long list of props inside the component by wrapping the data into a single object.

<Rajat
first="Rajat"
last="S"
job="Content Writer"
place="Bangalore"
/>

Here, I have a component name Rajat that has a number of props inside it. Right now, it has a few number of props, but in the future, the number of props may increase. In such cases, you can make your component accept an object instead of a long list of separate props.

<Rajat 
person={{
first:"Rajat",
last:"S",
job:"Content Writer",
place: "Bangalore"
}}
/>

This way, the component’s API will not change over time, even if you add new properties to it.

But you should avoid using configuration object if the component is destined to have a short list of props, as separate props tend to read more explicitly.

#7. Use SSR (Server-Side Rendering)

If you are going to build reusable components, it is important to decide if you want to support SSR with your components. Here are a few reason why SSR can be good for your reusable components:

  • Better Search Engine Optimization (SEO) — Google supports JavaScript parsing. But there are other many other search engines that don’t. Also, search engines are not entirely up front with what happens to the SEO of a client-side rendered component. So, its best to stay on the safer side of things and use SSR.
  • Better Performance — Rendering your component on the server improves performance by reducing the time it takes to first paint. Users don’t have to wait for the JavaScript to parse before seeing something on the screen.

There are a few things you need to keep in mind when rendering your component on the server-side:

  • Do not assume that your component is in a browser.
  • Avoid document and window calls.
  • Avoid using setTimeout.

#8. Single Responsibility Principle

This principle states that each component should have a clear, single responsibility. So if your component is a button, it’s responsibility should focus only on the button‘s functionality. The component should not contain anything that is not required by the button.

#9. Component libraries & Bit

Shopify, Airbnb, Pinterest and Uber, use a component design system to increase UI reusability, dev-velocity and consistency throughout the organization. Most of them use a UI component library (examples).

When building reusable React components, a component library can help boost consistency and reuse for these components.

Pinterest’s React UI component library “Gestalt”

Bit is an open-source platform for building applications using components.

For React components, it can increase dev-velocity and component reuse. You can use Bit as a standalone component system or combine it with your team’s component-library to make every component available to discover, use, develop an sync from any project.

With Bit, you can seamlessly isolate and share (without any refactoring) components from your library or different projects, make the visually discoverable, install them with NPM, import and develop them from any repository and even sync (update, merge) changes between your projects.

React title-list component made available with Bit

Conclusion

In this post, we saw how to create a reusable component that will render some text. Even though this is a very simple component and the real-world use-cases requires us to build way more complex components, the basic principle remains the same.

Next, we went through some of the best practices that helped me build better reusable components in React. These practices are:

  • Avoid weak wrapper elements.
  • Specify PropTypes and their defaults.
  • Avoid hard coding HTML IDs.
  • Declare Logical Defaults.
  • Use Config objects when your components have long list of props.
  • Use Server-Side Rendering.
  • Make your components more accessible.
  • Ensure that your component has a single responsibility.
  • Sharing components via a component library and/or Bit.

These practices are in no way a use for all use-cases kind. These are just what I have found to be useful for me. These might change or I might add more in the future. Feel free to comment and add you own suggestions.