DEV Community

Cover image for How does React allow creating custom components?
Nick
Nick

Posted on

How does React allow creating custom components?

React strives to give its users the ability to build encapsulated, reusable components, but how does it implement this logic in JSX?

Here is a simple example of a custom user-defined component, named Greeting. It renders inside a well-known App component.

// Greeting.jsx
const Greeting = ({name}) => {
  return <span>Hi, {name} 👋</span>;
}

// App.jsx
const App = () => {
  return (
    <div>
      <Greeting name="Nikita" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Let's break it down!

👉 How Greeting works?

  • Greeting is just a function, which returns JSX. JSX is syntax sugar for calling React.createElement
  • React.createElement expects three arguments:
    • type
    • props
    • children

Let's rewrite our Greeting component with this new knowledge.

// Greeting.jsx
const Greeting = ({name}) => {
  return React.createElement(
    'span', 
    null, 
    'Hi, ', name, ' 👋');
}
Enter fullscreen mode Exit fullscreen mode

👉 How to use the Greeting now?

Turns out, createElement expects three values as type:

  • tag name, like div or span
  • a class or a function, that defines custom component
  • React fragment type
// App.jsx
const App = () => {
 return React.createElement(
   'div',
   null,
   React.createElement(Greeting, {name})
 );
}
Enter fullscreen mode Exit fullscreen mode

Simply put, createElement calls the passed function internally and uses its return value to form the component tree.

// Internal intermediate result
const App = () => {
 return React.createElement(
   'div',
   null,
   React.createElement(
     'span', 
     null, 
     'Hi, ', 'Nikita', ' 👋'
   )
 );
}
Enter fullscreen mode Exit fullscreen mode

👉 Verify that it works yourself!

Go to reactjs.org, open the console and paste the last code snippet there.

Then call the App() and see the end result.
If it's the same as here 👇, you've done a great job!

{
  "type": "div",
  "key": null,
  "ref": null,
  "props": {
    "children": {
      "type": "span",
      "key": null,
      "ref": null,
      "props": {
        "children": [
          "Hi, ",
          "Nikita",
          " 👋"
        ]
      },
      "_owner": null
    }
  },
  "_owner": null
}
Enter fullscreen mode Exit fullscreen mode

P.S. Follow me on Twitter for more content like this!

Top comments (4)

Collapse
 
vijaysingh26 profile image
vijaysingh26 • Edited

In the code below, is the return statement a valid javascript? There are no quotes around the start and end of the value being returned. If I understand it correctly, Babel converts it to React.createElement function. How does Babel know that this snippet is a JSX snippet and not just an HTML?

// Greeting.jsx
const Greeting = ({name}) => {
return <span>Hi, {name} 👋</span>;
}

Collapse
 
vijaysingh26 profile image
vijaysingh26

Great article!! I now understand how React uses React.createElement to create the elements.
But when I looked at the javascript files of a React application using the "developer tools" I still saw the JSX snippets. I expected the JSX to be converted to Javascript by Babel before the code was deployed. Can you please explain why I still see JSX snippets in the javascript files?

Collapse
 
fromaline profile image
Nick

Hi! Thanks for the feedback! Really appreciate it. I suspect it's because you have source maps. Source maps are an industry standard, so you're probably using them. In a nutshell, they map Babel-processed JS files to the source code to make it easier to find bugs. Check out this StackOverflow question stackoverflow.com/questions/580572...

Collapse
 
vijaysingh26 profile image
vijaysingh26

@fromaline Thanks for that link about the source maps. After disabling the source maps I was able to see the "bundle.js". But the file doesn't contain direct calls to "React.createElement" function.
Is it because of something Babel does during compilation?