DEV Community

loading...

Build Your First Reusable Components Using React

Dimer Bwimba
Coding mean๐Ÿ‘:) ๐Ÿฅ‡ . Die having memories don't die with just dreams. Take care of your body, it's the only place you have to lv
ใƒป4 min read

Alt Text

Table of contents

1.What are reusable components?
2.Making a React component reusable
4.Conclusion

What are reusable components?

Reusable components are those React components that can be used multiple times in your application. As a result, they need to be generic enough so that itโ€™s free from complex business logic. If a component contains any complex logic inside it, not only does it become difficult to reuse, it also becomes less maintainable. React Hooks are the perfect fit for reusable component logic.

I'm straight up beginner , So if am lying on this `article` feel free to tell me ๐Ÿ˜ƒ

Let Goooo!๐Ÿฆธโ€โ™‚๏ธ

=> For example, the App component below has a button which canโ€™t be reused since it has the onClick prop hardcoded in it:

function handleClick(e) {
 // Some function which does fake API call
 fakeApiCall(e.target.value);
}

function App() {
 return (
   <div className="app">
     <button className="button" onClick={handleClick}>
       Submit
     </button>
   </div>
 );
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜ž Here, there is no way in which we can modify the text Submit which is rendered on the button.

๐Ÿ˜ŠBuuut Iiiif we want to make the above component reusable, we need to make it more generic. First, we can make a separate Button function which can be imported and reused multiple times in our application:

function handleClick(e) {
 // Some function which does fake API call
 fakeApiCall(e.target.value);
}

function Button() {
 return (
   <button className="button" onClick={handleClick}>
     Submit
   </button>
 );
}
Enter fullscreen mode Exit fullscreen mode

Then, we can reuse that Button component multiple times inside our App function:

function App() {
 return (
   <div className="app">
     <Button />
     <Button />
   </div>
 );
}
Enter fullscreen mode Exit fullscreen mode

The above code renders the following user interface like:


|Submit | |Submit |


๐Ÿค” As you can see ladyzz and gentlemanzz , we are already reusing one component multiple times. But, we still need to make it more generic because we might want to do different tasks with one click of a button. We can do a form submit, form reset or do another API call to fetch some sh** tone of data, for example.

Letโ€™s extract the handleClick function from our Button component and pass it as a prop. Our Button component will now look like the following:

function Button(props) {
 return (
   <button className="button" onClick={props.handleClick}>
     Submit
   </button>
 );
Enter fullscreen mode Exit fullscreen mode

And our App component will look like the following:

function handleClick(e) {
 // Some function which does fake API call
 fakeApiCall(e.target.value);
}

function App() {
 return (
   <div className="app">
     <Button handleClick={handleClick} />
   </div>
 );
}
Enter fullscreen mode Exit fullscreen mode

As you can see, we can pass any function to the Button component through the handleClick prop. I highly suggest that you check your props using PropTypes.

We can also use multiple Button components inside our App component:

function handleAPICall(e) {
 // Do some API call
}

function handleFormReset(e) {
 // Reset some form data
}

function App() {
 return (
   <div className="app">
     <Button handleClick={handleAPICall} />
     <Button handleClick={handleFormReset} />
   </div>
 );
}

Enter fullscreen mode Exit fullscreen mode

Alright, alright, alright ๐Ÿ˜Ž! As you can see, we have made our Button component even more flexible. We can also pass the text which is rendered on the button as a prop.

Our Button component will now look like the following:
๐ŸŽถ๐ŸŽถTanrara rara ๐ŸŽถ๐ŸŽถ ๐Ÿ˜Ž

function Button(props) {
 return (
   <button className="button" onClick={props.handleClick}>
     {props.label}
   </button>
 );
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜Ž And our App component will look like the following:

function handleAPICall(e) {
 // Do some API call
}

function handleFormReset(e) {
 // Reset some form data
}

function App() {
 return (
   <div className="app">
     <Button handleClick={handleAPICall} label="Submit"/>
     <Button handleClick={handleFormReset} label="Reset"/>
   </div>
 );
}
Enter fullscreen mode Exit fullscreen mode

It renders the following user interface like:


|Submit | |Reset |


Itโ€™s already very reusable.
But ๐Ÿ–๏ธ๐Ÿ”Š "hold on wait a minute "๐Ÿ”Šโ›”, we can also add certain additional props like whether to render an icon before the label of the button as well.

To do that, we can change our Button component to the following:

function Button(props) {
  return (
    <button className="button" onClick={props.handleClick}>
      {props.icon} {props.label}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

And, we need to pass that icon prop from our App component:

<Button
   handleClick={handleAPICall}
   label="Submit"
   icon={<i className="fas fa-arrow-alt-circle-right" />}
 />

Enter fullscreen mode Exit fullscreen mode

The above example uses font-awesome but you can use any font you want zaddy.

๐Ÿ‘‡
Also, itโ€™s a good idea to render the icon prop only if itโ€™s present. To do that, we just need to make the following changes to our Button component:

function Button(props) {
 return (
   <button className="button" onClick={props.handleClick}>
     {props.icon && props.icon} {props.label}
   </button>
 );
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ˜Ž Our component is very much reusable at this moment. We can also pass another additional prop called type which can control whether the button will be primary or secondary.

We need to make the following changes to our Button component:

function Button(props) {
 const className = `button ${props.type}`

 return (
   <button className={className} onClick={props.handleClick}>
     {props.icon && props.icon} {props.label}
   </button>
 );
}
Enter fullscreen mode Exit fullscreen mode

Here, we will be passing a type prop from our App component which will be passed to the className of the button.

Our App component will now look like the following:

function handleAPICall(e) {
 // Do some API call
}

function handleFormReset(e) {
 // Reset some form data
}

function App() {
 return (
   <div className="app">
     <Button
       handleClick={handleAPICall}
       label="Submit"
       icon={<i className="fas fa-arrow-alt-circle-right" />}
       type="primary"
     />
     <Button handleClick={handleFormReset} label="Reset" type="secondary" />
   </div>
 );
}
Enter fullscreen mode Exit fullscreen mode

We would also need to add a few lines of CSS to our application:

.button.primary {
 background-color: #0886ff;
}

.button.secondary {
 background-color: #73a800;
}
Enter fullscreen mode Exit fullscreen mode

Finally, we can distinguish between our #primary and #secondary buttons. Itโ€™s also a good idea now to add a #default #prop to our Button component so that it #renders #secondary buttons by #default. This is really helpful if we #forget to pass the #type #prop to our Button component. We need to make the following changes to our Button component:

function Button(props) {
 const className = `button ${props.type}`

 return (
   <button className={className} onClick={props.handleClick}>
     {props.icon && props.icon} {props.label}
   </button>
 );
}

Button.defaultProps = {
 type: "secondary"
};
Enter fullscreen mode Exit fullscreen mode

Now, if we have another Button component which doesnโ€™t have the type prop, it will be a secondary button:

<div className="app">
 <Button
   handleClick={handleAPICall}
   label="Submit"
   icon={<i className="fas fa-arrow-alt-circle-right" />}
   type="primary"
 />
 <Button handleClick={handleFormReset} label="Reset" type="secondary" />
 <Button handleClick={handleFormReset} label="Click" />
</div>
Enter fullscreen mode Exit fullscreen mode
๐Ÿค– "I will be back "

Follow me For Part II Tommmorrrrow , Honestly I just need a friends , but i will be back tho...

Discussion (4)

Collapse
alfredosalzillo profile image
Alfredo Salzillo ๐Ÿบ

Why the onClick is renamed in handeClick?
Also it's missing all the standard props of a button...

Collapse
dimer191996 profile image
Dimer Bwimba Author • Edited

I didn't really rename it, I just pass __callbacks as props_ for the onClick event , in our case the callback is handeClick.

But feel free to do it like this :

//reusable 
export function Button(props){
  return <button onClick={props.onClick}>
    {props.label}
  </button>
} 
//app
 export default function App(){
   function onClick(){
     alert("Hell yeees")
   }
    return <Button onClick={onClick} label=" fuck the police"/>
  }
Enter fullscreen mode Exit fullscreen mode

Play with the code right here
Also it's missing all the standard props of a button... ? Really Can you please Elaborate ๐Ÿค–

Collapse
alfredosalzillo profile image
Alfredo Salzillo ๐Ÿบ

If I need to pass the name attribute? And others a11y attributes? And others html button attributes? Or if I need to add a custom width?
The title of the article is "Build your first reusable components" bit this Button is not reusable. It's opinionated and can be used only in specific case, without the possibility to adapt it.
But most importantly you are missing all the a11y attributes.
The name of the article should be "create and use your first component".

Thread Thread
dimer191996 profile image
Dimer Bwimba Author • Edited

haha bruh , I said " first " , " first " , it's a starting point , again feel free to add more functionalities... for other use cases but keep it clean tho . And Yes It's reusable .

dev-to-uploads.s3.amazonaws.com/up...

Forem Open with the Forem app