Creating Reusable Components in React

Reusable components enhance development efficiency and consistency across the application. In this article, we will walk through the process of creating reusable components in React.

Below are the sub-topics covered in this article:

Why Create Reusable Components?

Reusable components are essential in React as they allow us to write modular, efficient, and maintainable code. By creating reusable components, we can:

  • Reduce code duplication
  • Improve code readability
  • Simplify maintenance and updates
  • Enhance reusability across the application

Component Design Principles

When designing reusable components, it is essential to follow key principles that ensure flexibility, maintainability, and scalability. Here are some guidelines to keep in mind:

  • Single Responsibility Principle (SRP): Each component should have a single responsibility and should not be responsible for multiple, unrelated tasks.
  • Separation of Concerns (SoC): Components should be designed to separate concerns, such as presentation, logic, and data.
  • Modularity: Components should be designed to be modular, allowing for easy composition and reuse.
  • Flexibility: Components should be flexible and adaptable to different use cases and scenarios.

Creating a Basic Component

Let us create a simple reusable component, SimpleButton, to demonstrate the process.

Step 1: Define the Component's Purpose and Requirements

Identify the component's purpose and requirements. In this case, we want to create a reusable button component that can be used throughout our application.

Step 2: Write the Component Code

Below screenshot displays the code for our SimpleButton component:

import { Button } from "primereact/button";
import PropTypes from "prop-types";
import { useState } from "react";

import "@css/ButtonStyle.scss";

function SimpleButton({ ...props }) {
  const [disabled, setDisabled] = useState(false);
  const [isLoading, setLoading] = useState(false);

  const handleOnclick = async (e) => {
    try {
      if (props.onClick) {
        const isPromiseObject = isAsyncFunction(props.onClick);

        if (isPromiseObject) {
          setDisabled(true);
          setLoading(true);
          props.onClick(e).then(() => {
            setDisabled(false);
            setLoading(false);
          });
        } else {
          props.onClick(e);
          setLoading(false);
        }
      }
    } catch (error) {
      setDisabled(false);
    }
  };

  const isAsyncFunction = (v) => Object.prototype.toString.call(v) === "[object AsyncFunction]";

  return (
    <>
      <Button
        {...props}
        className={`${props.className || "simpleButtonStyle"}`}
        type={props.type || "button"}
        onClick={handleOnclick}
        disabled={props.disabled || disabled}
        loading={isLoading || !!props?.loading}
      />
    </>
  );
}

SimpleButton.propTypes = {
  onClick: PropTypes.func, // Function to be called when the button is clicked
  className: PropTypes.string, // CSS class name for styling the button
  type: PropTypes.oneOf(["button", "submit", "reset"]), // Type of the button
  disabled: PropTypes.bool, // Whether the button is disabled or not
  loading: PropTypes.bool
};

export default SimpleButton;

Here, we are rendering the Button component from primereact/button and passing the following props:

  • className: We are using the className prop to apply styles to the button. We are using the simpleButtonStyle class by default, but also allowing the user to pass a custom class name as a prop.
  • type: We are using the type prop to set the type of the button. We are using the button type by default, but also allowing the user to pass a custom type as a prop.
  • onClick: We are using the onClick prop to call the handleOnclick function when the button is clicked.
  • disabled: We are using the disabled prop to disable the button if the disabled state variable is true or if the user passes a disabled prop.
  • loading: We are using the loading prop to show a loading indicator if the isLoading state variable is true or if the user passes a loading prop.

Handling Props and State

When creating reusable components, it is essential to manage props and state effectively. Here are some techniques to keep in mind for managing Props and State in reusable components

  • Prop Types: Define prop types using PropTypes to ensure that props are validated and documented.
  • State Management: Use React's useState hook to manage state in functional components.
  • Context API: Use the Context API to share state between components.

In our SimpleButton example, we are using useState to manage the component's state and PropTypes to define prop types.

Styling Components

When styling reusable components, it is essential to follow best practices that ensure consistency and maintainability. Here are some guidelines to keep in mind:

  • Use CSS Modules or CSS-in-JS: Use CSS modules or CSS-in-JS solutions like styled-components to scope component styles.
  • Use Class Names: Use class names to style components, rather than inline styles.
  • Define a Consistent Styling Convention: Establish a consistent styling convention throughout your application.

In our SimpleButton example, we are using a CSS module (ButtonStyle.scss) to style the component.

Key Takeaways

When creating reusable components, keep the following in mind:

  • Use props to pass data and functions to the component
  • Use state to manage the component's internal state
  • Use a consistent naming convention for props and state
  • Use PropTypes to define the component's prop types
  • Use a consistent CSS class naming convention

Related Topics

Using Reusable component
Changing the Color of Component and Page
Creating a New Page in React Project

 

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.