DEV Community

Cover image for How to be Better in React Code Reusability - Part2
Ahmed Radwan
Ahmed Radwan

Posted on • Originally published at nerdleveltech.com

How to be Better in React Code Reusability - Part2

How Can We Achieve Reusability in React?

Step 1: Identify the Reusable Component

The first step in creating a reusable component in a React application is to identify the particular component used that needs to be made reusable. Look for components that are used in multiple places throughout the application and have similar functionality.

Step 2: Determine the Component's API

The second step in creating a reusable component in React is to determine the component's API, or the set of properties and methods that the component will expose to other components. The API should be well-documented and easy to use.

Step 3: Write the Component's Code

The third step in creating a reusable component in React is to write the component's code. The code should be clean, easy to read, and well-organized. The component should be designed to be flexible and customizable, with a clear separation of concerns.

Step 4: Test the Component

The fourth step in creating a reusable component in React is to test the component. The component should be tested thoroughly to ensure that it works as expected and that react components can handle various use cases.

Step 5: Publish the Component

The final step in creating a reusable component in React is to publish the component. The component can be published as a package on a package manager like npm, or it can be shared as a component library within the organization.

Here is an example of a reusable component in React that displays a list of items:

import React from "react";

function ItemList(props) {
  const { items, renderItem } = props;

  return (
    <ul>
      {items.map((item, index) => (
        <li key={index}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}

export default ItemList;

In this example, the ItemList component is a reusable component that displays a list of items. It takes two props: items, which is an array of items to be displayed, and renderItem, which is a function that takes an item as an argument and returns the JSX to be rendered for that item.

The ItemList component's API is well-defined: it takes an array of items and a function to render each item. This makes the component flexible and customizable, and allows it to be used in various contexts.

The code for the ItemList component is clean, easy to read, and well-organized. The component is designed to be flexible and customizable, with a clear separation of concerns.

The ItemList component should be thoroughly tested to ensure that it works as expected and can handle various use cases. Once the component has been tested and is ready for use, it can be published as a package or shared as a component library within the organization.

Four Major Challenges React Developers Face

When sharing components across multiple projects in React, conflicts and naming collisions can arise. These issues can be addressed by following these best practices:

Use Unique Namespaces

Using unique namespaces can help to avoid naming collisions. A namespace is a prefix that is added to a component's name to make it unique. For example, if two projects use a component called Button, one project could add a namespace of ProjectA to the component, and the other project could add a namespace of ProjectB to the component.

// In Project A
import { Button as ProjectAButton } from "component-library";

// In Project B
import { Button as ProjectBButton } from "component-library";

In this example, the Button component from the component-library package is imported with a different name in each project, using a namespace to the class component to make it unique.

Use Scoped Packages

Using scoped packages can help to avoid conflicts between packages. A scoped package is a package with a name that includes a scope, such as @my-org/my-package. Scoped packages are guaranteed to be unique, making it easy to avoid naming collisions.

npm install @my-org/component-library

In this example, the component-library package is a scoped package with the scope @my-org. This makes it easy to avoid naming collisions between packages.

Use Versioning

Using versioning can help to avoid conflicts between different versions of a package. When a package is updated, the version number is incremented. By specifying a version number when installing a package, you can ensure that you are using a specific version of the package.

npm install component-library@1.0.0

In this example, the component-library package is installed at version 1.0.0. By specifying the version number, you can ensure that you are using a specific version of the package and avoid conflicts with other versions.

Document Dependencies

Documenting package dependencies can help to avoid conflicts between packages. By documenting the package dependencies, you can ensure that the correct versions of packages are used together.

{
  "dependencies": {
    "react": "^16.8.6",
    "component-library": "^1.0.0"
  }
}

In this example, the component-library package is listed as a dependency in the package.json file. The version number is specified with a caret (^), which means that the package can be updated to a newer minor or patch version, but not a newer major version. By specifying the correct version of the package, you can ensure that it is used with the correct version of other packages and avoid conflicts.

Managing Dependencies of Reusable Components

When creating reusable components in React, it is important to manage dependencies effectively. Dependencies are external packages or modules that a component relies on to function. Here are some best practices for managing dependencies of reusable components:

Use Package Managers

Use a package manager like npm or Yarn to manage dependencies. Package managers make it easy to install and update dependencies, and ensure that the correct versions of dependencies are used.

npm install my-component-library

In this example, the my-component-library package is installed using the npm package manager.

Specify Dependencies

Specify the dependencies of a component in the component's documentation or in the package.json file. This makes it clear which dependencies the component relies on.

{
  "name": "my-component-library",
  "version": "1.0.0",
  "dependencies": {
    "react": "^16.8.0",
    "lodash": "^4.17.20"
  }
}

In this example, the my-component-library package specifies the react and lodash packages as dependencies in the package.json file.

Use Peer Dependencies

Use peer dependencies to specify dependencies that are expected to be provided by the consumer of the component. Peer dependencies are dependencies that are not installed with the component, but are expected to be installed by the consumer.

{
  "name": "my-component-library",
  "version": "1.0.0",
  "peerDependencies": {
    "react": "^16.8.0",
    "lodash": "^4.17.20"
  }
}

In this example, the my-component-library package specifies the react and lodash packages as peer dependencies in the package.json file. This means that the consumer of the component is expected to install these packages separately.

Keep Dependencies Up-to-Date

Keep dependencies up-to-date by regularly updating them to the latest version. This can help to ensure that the component is compatible with the latest versions of its dependencies.

npm update my-component-library

In this example, the my-component-library package is updated to the latest version using the npm package manager.

Test with Different Versions of Dependencies

Test the component with different versions of its dependencies to ensure that it is compatible. Use a tool like npx create-react-app to create a new React project with the desired versions of the dependencies. Then, import the component and test it in the new project.

import React from "react";
import ReactDOM from "react-dom";
import MyComponent from "my-component-library";

ReactDOM.render(<MyComponent />, document.getElementById("root"));

In this example, the MyComponent component from the my-component-library package is imported and used in a new React project with the desired versions of the dependencies. This can help to ensure that the component is compatible with the desired versions of the dependencies.

Conclusion

To sum it up in clear points, here are the key steps to follow:

  • Keep Components Small and Function-Specific

It is important to keep components small and to the point of a specific task. This makes it easier to reuse the component in different contexts and reduces the likelihood of conflicts with other components.

  • Use Higher-Order Components (HOC)

Higher-order components are functions that take a component as an argument and return a new component with additional functionality. This can help to improve code reusability by separating concerns and making it easier to add or remove functionality.

  • Use Render Props

Render props are a pattern where a component receives a function as a prop, which it then calls to render content. This can help to improve code reusability by allowing components to be more flexible and customizable.

  • Use Context

Context is a way to share data between components without having to pass props down through the component tree. This can help to improve code reusability by making it easier to share data between components and reducing the need for prop drilling and unnecessary rendering.

  • Use React Hooks

React hooks are functions that allow functional components to use state and other React features that were previously only available in class components. Hooks can help to improve code reusability by making it easier to share logic between components and reducing the need to duplicate code for higher-order components.

In conclusion, code reusability is an important aspect of building maintainable and scalable applications in React. By following the best practices outlined in this article and the previous one, you can create reusable components that are flexible, customizable, and easy to maintain.

Top comments (1)

Collapse
 
corners2wall profile image
Corners 2 Wall

Funny point:
import { Button as ProjectAButton } from "component-library"
In this case, your jsx layout will be strange:
<ProjectAButton>
Aboba
</ProjectAButton>

I know what problem you are trying solve but if you are using monorepo consisting of many many projects - yes it's really become problem search file by component name. I can find easy solve this: you can open your project in different folder, ide solves all your problems with name collisions