DEV Community

Cover image for How React components work?

How React components work?

React Components are the fundamental building blocks of any React app. They allow us to simplify complex UIs by breaking them down into small chunks.

But as always every abstraction has its cost and the very concept of React Components confuses a lot of beginners, so let's figure it out!

React Component vs React Component instance vs React Element

These three terms seemingly refer to a single thing - UI element on the screen. But it's not true.

React Component

React Component is either a function or an ES6 class - nothing more, nothing less. You manage the state, handle events and implement other custom logic here.
It never renders anything to the screen. Instead, you create its instance to do that.

const TextButton = ({text}) => {
  return <button>{text}</button>;
}

// It becomes more obvious with class-based component
// because you extend React.Component, not React.Element
class ListItem extends React.Component {
  render() {
    return <li>{this.props.children}</li>;
  }
}
Enter fullscreen mode Exit fullscreen mode

React Component Instance

It's exactly what it sounds like. You may have an instance of the React Component only at run time.
Also, you may have multiple instances, each with its own properties and local state. It happens when you use React Component more than once.

class ListItem extends React.Component {
  constructor(props) {
    super(props);
    console.log(`This is instance ${this}`);
  }

  render() {
    return <li>{this.props.children}</li>;
  }
}

const App = () => {
  return (
    <ul>
      <ListItem>First item</ListItem>
      <ListItem>Second item</ListItem>
      <ListItem>Third item</ListItem>
    </ul>
  );
}
Enter fullscreen mode Exit fullscreen mode

React Element

React Element is what React Component Instance returns at run-time. It's a plain JavaScript object that completely describes a DOM node.
Multiple React Elements together form a virtual DOM, a tree-like structure that describes the UI of your React app.

// After Babel
const App = () => {
  return React.createElement('ul', null, 
    React.createElement(ListItem, {children: 'First item'}),
    React.createElement(ListItem, {children: 'Second item'}),
    React.createElement(ListItem, {children: 'Third item'})
  )
}

// At run-time
const App = () => {
  return {
    "type": "ul", 
    "key": null, 
    "ref": null, 
    "props": { 
      "children": [
        { 
          "type": class ListItem,
          "key": null, 
          "ref": null, 
          "props": { 
            "children": "First item" 
          },
        },
        // ...
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The big picture of how React Components work

  1. React developers create either function-based or class-based React Components, that return JSX.
  2. Babel transpiles JSX to React.createElement() or jsx() at build-time.
  3. React creates necessary React Components Instances at run-time, and they return React Elements.
  4. ReactDOM renders the virtual DOM, that consists of React Elements.

P.S. That's all for today! Follow me on Twitter for future content!

Discussion (12)

Collapse
lukeshiru profile image
Luke Shiru

Is worth mentioning that nowadays is recommended to avoid class components because since hooks that they don't provide any value over functional components. Here's a great comparison but basically you have way less "unnecessary" code when you work with functional components, compared to they class based counterpart.

Cheers!

Collapse
fromaline profile image
Nick | React tinkerer ⚛️ Author

Yep, I agree with you for the most part.

Functional components are much cleaner, and I prefer them over class-based ones. The same goes for other developers I know in person.

But at the same time, there is no official recommendation to avoid class-based components. For example, people with a strong OOP "background" would probably prefer class-based components. Because they at least partially follow the OOP paradigm.

Thanks for adding value to the conversation!

Collapse
virajsingh19 profile image
Viraj Singh

I've seen many codebases using hooks most of the time and a top level Class component for Error boundary, as there's no official error boundary hook available.

Thread Thread
lukeshiru profile image
Luke Shiru

If you use Preact, it has an official hook for error boundaries, and React has several "unofficial" but good ones in NPM. Still having to use one class because of limitations with the library hardly counts as "using classes". If you check the new beta docs for React, all the examples and introductory content uses functional components 😊

Thread Thread
fromaline profile image
Nick | React tinkerer ⚛️ Author

Yes, it's another proof that we still need both ways of creating components!

Thread Thread
lukeshiru profile image
Luke Shiru

Arguable. There are npm packages to use hooks instead of a single class in your codebase just to handle errors. Error boundaries exist only for when you write code that throws (you shouldn't, btw) or if you use a library that throws (you should avoid those as much as possible), and even if you write the class yourself, an error boundary is kinda different to a regular Component, so you don't need to know regular components to write an Error Boundaries (besides you'll probably write only one and never touch it again 😅). Besides hook libraries, you can also use context if you want to handle errors in a common way in the entire app 😊

Thread Thread
fromaline profile image
Nick | React tinkerer ⚛️ Author • Edited on

I get your point, but why are you so against class-based components?
Is it just personal preferences? Or have you had some bad experiences using them?

Thread Thread
lukeshiru profile image
Luke Shiru

I'm generally against anything that makes me or my teammates write more code with not real value added to that. Don't get me wrong, I love OOP almost as much as FP, but classes aren't the best method of encapsulation in JavaScript/TypeScript, we have closures and modules for that. In React in particular, as I previously mentioned, it doesn't make sense to use class based components when the function components are way less convoluted. Just a simple button goes from this:

const FancyButton = props => <button className="fancy" {...props} />;
Enter fullscreen mode Exit fullscreen mode

To this:

import { Component } from "react";

class FancyButton extends Component {
    render() {
        return <button className="fancy" {...this.props} />;
    }
}
Enter fullscreen mode Exit fullscreen mode

Way more "boilerplate" for something that simple. Even if you have a strong class based language background like Java or C++ (I had), it doesn't make sense to write more just to keep using "class", when you can just achieve the same and more with way less code. I have an entire article talking about why you might not need classes, and I have an ongoing series of articles that goes over "writing less code with the same value and more readability", so I tend to advice against class every time I see it floating around, unless it actually makes sense (which generally does not, in my experience).

Thread Thread
fromaline profile image
Nick | React tinkerer ⚛️ Author

Wow, such a cool comment!
I'll check out your articles, thanks!

Collapse
fromaline profile image
Nick | React tinkerer ⚛️ Author

More info on this here!

Collapse
alguercode profile image
alguerocode

good blog bro

Collapse
fromaline profile image
Nick | React tinkerer ⚛️ Author

Thanks 🙏🏻
I truly appreciate such feedback!

Also, I have other articles here if you want more content like this.