Blog

Understanding the Difference Between React Elements and Components

React is pretty popular here at Quick Left. Most new development on Sprintly is done with React, we recommend it to our clients, and Sam even leads React training courses.

When I first started learning about React, I had trouble understanding the difference between React Elements and React Components. Despite reading through the React guide, I couldn’t quite get to that ah-ha moment. So I went exploring.

Starting Simple

I started experimenting with the render method of a component that creates some basic mark-up:

class Post extends React.Component {
  render() {
    return (
      <article>
        <h2>{this.props.title}</h2>
        <section>{this.props.children}</section>
      </article>
    );
  }
}

This simple component wraps its children in a few elements and adds a title. So what exactly does this render method return? Once you know that React converts JSX like <article> into function calls like React.createElement("article"), it becomes clear that it returns a tree of React Elements, with a top-level "article" element:

// Don't do this, BTW.
new Post({}).render();
// => ReactElement { type: "article", … }

So far, so good. This is the “Virtual DOM” the kids keep talking about. The render method returns a description of what the DOM should look like, and then React efficiently updates the real DOM to match.

Adding a Component

It would make sense if React Elements just translated to real DOM elements. But rendering is not limited to the existing DOM elements. Any React Component can be used as well. To experiment with this, I created a simple app that renders a Post:

class MyApp extends React.Component {
  render() {
    return (
      <div>
        <h1>My Cool App</h1>
        <Post title="Welcome">
          <p>Hello There!</p>
        </Post>
      </div>
    );
  }
}

Looking at this code, my initial impression was that this render method would create a Post component. I expected <Post>…</Post> to be converted into something like new Post(…). Sure, React uses lightweight virtual elements as placeholders for real DOM elements, but there isn’t a real Post element, so it must create a Post Component here, right? (Wrong.)

In reality, <Post> still turns into a call to createElement(), just like <article> did. And the create-element call still returns a lightweight virtual-DOM element. The only difference is that in this case, the element’s type is set to the class Post, rather than the string "article":

// Don't do this either, FYI.
new MyApp().render().props.children[1];
// => ReactElement { type: function Post(…) {}, … }

This kind of fried my brain. If a Post wasn’t created when I rendered the app, when was it created?

Ah-Ha

For me, the key to understanding this was realizing that, in React land, there is a <Post> element. The only difference between <article> and <Post> is that one is implemented natively by the browser, and one is implemented through my Post component class. (If you’re into web technologies, this probably sounds familiar.) Rendering always creates virtual-DOM nodes. Some of those virtual nodes, like the one with type "article", map to native DOM elements. Others, like the one with type Post, map to custom DOM elements. Component authors implement custom elements, just like browser authors implements native elements.

When an element is rendered into the page, using something like React.render(<MyApp/>, document.body), React creates a real DOM from the virtual DOM. For virtual nodes that map to native DOM elements, it creates native DOM elements. For virtual nodes that map to custom DOM elements, it creates components. (This is a simplified description, but it illustrates the idea.)

When an element is re-rendered, React preserves and updates existing components in the same way that it preserves and updates existing native DOM elements. The Post Component’s lifecycle is tied directly to the presence of the <Post> Element when the app is rendered.

Conclusions

One of the great things about React is that it manages the life cycles of your components. Using a library like Backbone where you manage your own view hierarchy, it’s all too easy to accidentally leave behind a subview when tearing down a section of your UI. However, just like all systems that “manage things for you,” it can be difficult to understand what is actually going on. Happily, React is all “just JavaScript” under the hood. So if you do want to dig into how it works, it’s easy to figure out how to do so.

If you want to learn more about React Elements and Components, the DOM terminology page and composition example in the React guide are great resources.

Happy digging!