Reusable Component in React - Is It Really Shareable?
A lot of students ask me what are reusable components, how to know that we need to make something reusable and is it really a good idea to always try and implement reusable components inside your frontend framework.
The first and really important point is to think about your components as reusable functions.
We can apply to the functions the same rules as for components.
Just imagine that we implement some feature and it looks really big. At least your file is huge (maybe 200 lines or more). At this moment you typically thing that you must split it in several components.
Then you have some questions.
Should it be reusable?
The first question is do we need to make it reusable at all? Maybe not. But your component is big and it is difficult to read it. What you can do?
You can move part of your component out and simply split in 2 different components
Just imagine that we implement the feature which is called register page.
/register
/components
Main.jsx
This is why we have a folder register
with components folder and a single Main
component which is extremely big. So we want to split it. We can just take a part of it and move it. We don't need to make it sharable and we just put it near.
/register
/components
Main.jsx
Form.jsx
So we moved our form our of register component. We didn't do it reusable at all. We simply moved it out as easy as possible.
I wrote example like we are talking about React but all these rules can also be applied to Vue, Angular or any other framework.
The main idea is not to make something reusable but just to split your huge component which makes it easier to support. All these components are still living in register
folder. They are completely isolated inside our register feature and they are not reusable. This is why you should not think a lot about how to move them out.
Make it shareable between features
At some point you might implement login
page
/login
/components
Main.jsx
Form.jsx
Here you also started just with Main
file, it became huge and you moved a form out of Main
. But it is still not reusable. This is totally fine, your code is easier to support.
At that specific moment you might think "But I have similar form in register and login pages. I must for sure share them". Is it always a good idea? It depends.
From my experience in a lot of cases it is much easier to copy paste code than to share it. It is easier to change and it is faster to ship.
If you try to make something shareable which is not really shareable you always have problems that you write if conditions and you check that if you are inside register
page then you do this and inside login
are do that.
This is a bad approach and a sign that your component is not really shareable.
Your shareable component should never have cases with specific implementation.
For example this form that you see here is a fully configurable form. Something similar you can build between register
and login
.
So for this case we want to change our structure.
/register
/components
Main.jsx
/login
/components
Main.jsx
/shared
/components
Form.jsx
Now we moved it to shared
folder which allowed us to remove it from both features. Most importantly it must be configurable and it should not have any logic related to either register
or login
.
Real example - loading
Now I want to show you some real examples of shareable components so you understand better when they are really shareable. All examples that I want to show you are coming from my Angular + NgRx course.
Here we have lots of different reusable components. These are Angular components but the same rules you can apply to any component.
First of all let's look on something simple. We have a loading
component which is extremely simple.
// src/app/shared/components/loading/loading.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'mc-loading',
template: '<div>Loading...</div>',
standalone: true,
})
export class LoadingComponent {}
It doesn't have any logic but just some markup which allows us to reuse loading
component at any place of our application.
Real example - error message
We can have something similar (where we just render some markup) but with possibility to configure it through inputs.
// src/app/shared/components/errorMessage/errorMessage.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'mc-error-message',
template: '<div>{{message}}</div>',
standalone: true,
})
export class ErrorMessageComponent {
@Input() message: string = 'Something went wrong';
}
Here we have an errorMessage
component which we can configure with the inputs.
Real example - pagination
We can also have a shareable component with some business logic inside. For example pagination
component can be reused for different pages. Let's say you are rendering a list of users and on the other page a list of articles.
// src/app/shared/components/pagination/pagination.component.html
<ul class="pagination">
<li
*ngFor="let page of pages"
class="page-item"
[ngClass]="{ active: currentPage === page }"
>
<a [routerLink]="[url]" [queryParams]="{ page: page }" class="page-link">
{{ page }}
</a>
</li>
</ul>
And some logic
// src/app/shared/components/pagination/pagination.component.ts
import { CommonModule } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core';
import { RouterLink } from '@angular/router';
import { UtilsService } from 'src/app/shared/services/utils.service';
@Component({
selector: 'mc-pagination',
templateUrl: './pagination.component.html',
standalone: true,
imports: [RouterLink, CommonModule],
})
export class PaginationComponent implements OnInit {
@Input() total: number = 0;
@Input() limit: number = 20;
@Input() currentPage: number = 1;
@Input() url: string = '';
pagesCount: number = 1;
pages: number[] = [];
constructor(private utilsService: UtilsService) {}
ngOnInit(): void {
this.pagesCount = Math.ceil(this.total / this.limit);
this.pages =
this.pagesCount > 0 ? this.utilsService.range(1, this.pagesCount) : [];
}
}
So can configure our pagination
and inside we have some business logic to create a list of pages.
Real example - popular tags
Another shareable component is a full blown feature. It has not only markup and business logic inside but also a state, working with API and much more. In our case popularTags
is such component.
As you can see we have not only a component but also a service, store of NgRx and some internal types. We can render popularTags
in any place of our application and it will fetch needed data from API, store them in state and render inside.
And the most important point to remember is that it is much more difficult to make something shareable and reusable. This is why copy paste is a winner in a lot of cases.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!