React Tips — Component Organization and Web Components

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

React is the most used front end library for building modern, interactive front end web apps. It can also be used to build mobile apps. In this article, we’ll look at some tips and tricks to make building apps with React easier.

Keeping Components Small

Keeping components small making them easy to read, change, and test. They’re also easier to debug and maintain. It’s more than 30 lines of code, it’s probably too big.

We can easily split up components into smaller ones by passing props between them if they’re parent and child.

If they aren’t related, we can also use a state management solution like Redux or the context API.

They do less and so they’re more likely to be reused since they fit more use cases.

For example, the following is a small component:

import React from "react";

export default function App() {
  const [count, setCount] = React.useState(0);
  return (
    <div className="App">
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <p>{count}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

It’s short and it doesn’t do much on its own.

Avoid Components That are Too Small

Components that are too small are also a problem. We don’t want lots of components that are one or 2 lines. Also, we don’t want every div, span, or paragraph to be its own component.

We should make them reusable by letting them accept props. For instance, we shouldn’t have components that are like this everywhere in our app:

const Foo = <p>foo</p>;
Enter fullscreen mode Exit fullscreen mode

Using Web Components in React

We can put web components straight into React components and use them.

For instance, we can define a web component and then use it as follows:

import React from "react";

class FooParagraph extends HTMLElement {
  constructor() {
    super();
  }

  connectedCallback() {
    const shadow = this.attachShadow({ mode: "open" });
    const p = document.createElement("p");
    p.setAttribute("class", "wrapper");
    p.textContent = this.getAttribute("text");
    shadow.appendChild(p);
  }
}

customElements.define("foo-paragraph", FooParagraph);

export default function App() {
  return (
    <div className="App">
      <foo-paragraph text="abc" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the FooParagraph web component class. Inside the class, we have the connectedCallback , which gets the attribute value for text and then add a p tag with the text ‘s value into the shadow DOM.

Then we call customElements.define to define a new web component. And then we put it straight into the App React component.

Using React in Our Web Components

We can also create web components with React by mounting our React component inside a web component as follows:

src/index.js :

import React from "react";
import ReactDOM from "react-dom";

class XParagraph extends HTMLElement {
  connectedCallback() {
    const mountPoint = document.createElement("div");
    this.attachShadow({ mode: "open" }).appendChild(mountPoint);

    const text = this.getAttribute("text");
    ReactDOM.render(<p>{text}</p>, mountPoint);
  }
}
customElements.define("x-paragraph", XParagraph);
Enter fullscreen mode Exit fullscreen mode

index.html :

<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app"></div>
    <x-paragraph text="foo"></x-paragraph>
    <script src="src/index.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

The code above are parts of a project that’s created with Parcel. Therefore, we can use modules in a script.

We have a XParagraph web component that has the ReactDOM.render call to render a p React element with the text attribute’s value taken from the attribute of the web component.

Then we defined the web component with customElements.define with the name of the element as the first argument, and the HTMLElement class as the second argument.

In index.html , we added the x-paragraph web component with the text attribute set to foo , so that we display the text content inside the element by calling this.getAttribute('text') and then passing in the returned value to ReactDOM.render .

Therefore, we see the word ‘foo’ on the screen.

Conclusion

To make development, testing, and reading the code easy, we should keep components small. Around 30 lines or less is a good size.

However, they shouldn’t be too small, like 1 or 2 lines, since we would have to manage too many of them. That’s even worse if they don’t take any props. To make sure that they’re reusable, we should make sure that they take props if they share any data.

React components can be embedded into web components to create easily reusable web components with React.

Also, we can embed web components in a React component so that we can take advantage of standards-compliant custom HTML elements that we can use anywhere.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .