How to Reuse React Components Across Your Projects

ni
nitsan7702 weeks ago

Finally, you completed the task of creating a fantastic input field for the Input in your app. You are happy with the outcome and will continue to work on your assignments.

Next week, a team leader from another team asks you for help: "I need this done as soon as possible. Would you be able to lend a hand?" You happily accept.

Your organization tries to maintain a consistent brand, so you're not surprised to find that they want you to build a similar input element as you built a week ago.

"I'll just copy and paste from my team's repository", you say to yourself. Copying and pasting is not difficult, but what if we want to add styles to the input? You'll have to change all occurrences of it. If there are only two components, it's fine, but what if there are hundreds?

In this blog post, you will learn how to reuse every component that you have created using Bit. This is not a mistake. The components you create can easily be reused across all of your organization's apps. Ready. Set. Let's go!

Setting up our Workspace

Clearly, we want to reuse that input component, but we don't want to copy-paste since it is not scalable, so what can we do?

Using Bit, we can extract the input component. Bit will handle everything for us, from versioning, building, testing, and even managing our component dependencies.

Installing Bit is as simple as running a single command:

npx @teambit/bvm install
Copied

Now at the root of our project, we can initialize a Bit Workspace from a React template:

bit new react reusing-react-components --empty --skip-git --default-scope [your-cloud-user-name].[your-scope-name]

cd reusing-react-components
Copied

Workspaces serve as development and staging areas for components. We create new components, retrieve and modify existing ones, and combine them.

Workspace makes your development experience seamless as if it were a monolith, yet it remains distributed and highly scalable. Components are not stored in the Workspace. Regardless of whether they're stored on bit.cloud or on the local server, they can be imported into Workspace.

Let's make our first Reusable React component!

bit create react ui/input
Copied

You can either copy the files from this folder into the generated folder(UI/input) follow this guide and copy the snippets into the files.

Here is the source code for the input implementation:

input.tsx
import React from 'react';
import { Button } from '@nitsan770/reuse-components.ui.button';
import classNames from 'classnames';
import styles from './input.module.scss';

export type InputProps = {
  buttonText: string;
} & React.InputHTMLAttributes<HTMLInputElement>;

export function Input({ buttonText, className, ...rest }: InputProps) {
  return (
    <div className={classNames(styles.inputContainer, className)}>
      <input {...rest} className={styles.inputText}></input>
      <Button className={styles.button} children={buttonText} />
    </div>
  );
}
Copied

Since we have Button and classNames as dependencies, we'll have to install them in our Workspace:

bit install @nitsan770/reuse-components.ui.button classnames
Copied

In the generated folder, create a file called input.moudle.scss and insert this CSS:

input.module.scss
.inputContainer {
  height: 56px;
  min-width: 320px;
  display: flex;
  flex-direction: column;
  justify-content: stretch;
  align-items: stretch;
  position: relative;
  .button {
    position: absolute;
    width: 103px;
    height: 40px;
    right: 8px;
    top: 8px;
    width: 30%;
  }
  .inputText {
    border: none;
    background-color: var(--bit-bg-dent, #f6f6f6) !important;
    color: var(--bit-text-color-heavy, #2b2b2b);
    height: 100%;
    width: 100%;
    border-radius: 8px;
    &.error {
      border: var(--bit-error-color, #e62e5c) 1px solid;
      background-color: var(--bit-error-color, #e62e5c);
    }
    &:focus,
    &:active,
    &:hover {
      border: var(--bit-accent-color, #6c5ce7) 1px solid;
    }
  }
}

.disabled {
  opacity: 0.5;
}
Copied

The component will be added to the .bitmap file:

"ui/input": {
  "scope": "",
  "version": "",
  "defaultScope": "nitsan770.reuse-components",
  "mainFile": "index.ts",
  "rootDir": "ui/input",
},
Copied

Let's have a look at the lovely independent component in the Workspace UI:

bit start
Copied

The development server is up and running! However, we are unable to see anything 😔 . This is because we have not created any compositions for our newly created component.

Compositions allow components to be simulated in different variations. These can then be used for testing, visualization, and discoverability.

Let's create a composition for our component:

input.composition.tsx
import React from 'react';

import { Input } from './Input';

export const BasicInput = () => <Input buttonText="Submit" />;
Copied

Now we can see the component in the Workspace UI:

basic input

Yet it is difficult to understand how it works. Let's write some documentation.

Bit components' documentation is written in MDX. No more boring sentences; now you can embed anything you want to make your component more visually appealing.

input.docs.mdx
---
description: An input element with a built-in button.

labels: ["input", "submit form"]
---

import { Input } from "./input";

### Modify the text on the button

'''js live

<Input buttonText="Go" />

'''
Copied

It looks much better now, and consumers can try out the component before installing:

Last but not least, a good component is well-tested:

input.spec.tsx
import React from 'react';
import { screen, render } from '@testing-library/react';
import { BasicInput } from './input.composition';

it('Renders the input', () => {
  render(<BasicInput />);
  const input = screen.getByRole('textbox');
  expect(input).toBeInTheDocument();
});

it('Renders the button', () => {
  render(<BasicInput />);
  const button = screen.getByRole('button');
  expect(button).toBeInTheDocument();
});

it('Renders the button text', () => {
  render(<BasicInput />);
  const button = screen.getByRole('button');
  expect(button).toHaveTextContent('Submit');
});
Copied

Let's run the tests:

bit test
Copied

All tests have passed. 🎉

PASS src/input/input.spec.tsx
  ✓ Renders the input (67 ms)
  ✓ Renders the button (19 ms)
  ✓ Renders the button text (12 ms)



Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 5.549 s
Ran all test suites.
test has been completed in 13.718 seconds.
Copied

Our last step is to tag the component with a (first) version number.

bit tag -m "first version"
Copied

When a component is tagged, it will also go through a build process in addition to locking the current state of the source files.

In this process, the component will be compiled to a distributable format and packed into a tar file.

Once the component has been tagged, it's time to publish it:

bit login

bit export
Copied

The component will be exported to the remote scope on bit.cloud.

Now that it has been published, we can use it in any React project.

Let's try it out!

Open another React project:

npx create-react-app another-project
Copied

You can install the component using npm, yarn, or pnpm. Let's use pnpm:

choose pnpm
pnpm i @nitsan770/reuse-components.ui.input
## if you haven't yet, remember to add your bit.cloud account as a scoped registry:
# npm config set '@nitsan770:registry' https://node.bit.cloud
Copied

We can now use the component in the app.js file:

import logo from './logo.svg';
import { Input } from '@nitsan770/reuse-components.ui.input';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <Input buttonText="Submit" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
Copied

Let's run the dev server:

npm start
Copied

It's a perfect match!

dev server running

Collaboration on components

As we move forward, a friend of yours is tasked with refactoring your component to support additional properties.

One of my favorite things about Bit is the ease with which you can create new workspaces, import any component into them, and start working.

Let's create another Workspace to simulate collabrion with our friend.

bit new react our-friends-workspace --empty --skip-git --default-scope [your-cloud-user-name].[your-scope-name]

cd our-friends-workspace
Copied

Retrieving the component into our newly created Workspace is only a matter of running one single command:

bit import nitsan770.reuse-components/ui/inpu
Copied

bit import command is like a siemens twin to a bit workspace. If they are separated, they will both die.

Using Bit Import, we can retrieve any component into our local workspace, edit it and the tag, and export it with a new version.

Let's add a new prop to our Input component:

input.tsx
import React from 'react';
import { Button } from '@nitsan770/reuse-components.ui.button';
import classNames from 'classnames';
import styles from './input.module.scss';

export type InputProps = {
  buttonText: string;
  disabled?: boolean;
} & React.InputHTMLAttributes<HTMLInputElement>;

export function Input({
  buttonText,
  disabled,
  className,
  ...rest
}: InputProps) {
  return (
    <div className={classNames(styles.inputContainer, className)}>
      <input {...rest} disabled={disabled} className={styles.inputText}></input>
      <Button className={styles.button} children={buttonText} />
    </div>
  );
}
Copied

It's time to tag it again. Naturally, you'll want to add new tests and compositions, but we won't do it here.

bit tag -m "added the disabled prop"
Copied

Of course, we must export it so that everyone can experience this wonderful change:

bit export
Copied

Once we are back in our original workspace, we can update by running...you guessed it - bit import!

cd reusing-react-components
bit import
Copied

To see the changes in the source files, we will also need to checkout the latest version:

bit checkout latest -a
Copied

Now we're in sync with our friend's update :D

In addition to that, there's more. We can now also update the component in the React project we installed it in because Bit publishes a new package every time we tag our component:

cd another-project
pnpm update @nitsan770/reuse-components.ui.input
Copied

We now have our updated button in the React project :)

Summary

Our objective in this guide was to learn how to create reusable components using Bit.

We explored the process of creating a component from scratch and learned about all the parts (files) that make up a complete component.

We also saw how to install the component in any React project.

Last but not least, we learned how to collaborate on a component, get updates and stay in sync with each other.

This tutorial was hopefully enjoyable for you. I am sure that there is more that can be learned.

Please read our documentation if you want to learn more.

If you have any questions, please ask them in our slack channel.

Best of luck!