SoFunction
Updated on 2025-03-10

Detailed explanation of the difference between React elements and components

Starting from the problem

I've been asked a question like this:

Want to achieve oneuseTitleMethods, specific usage examples are as follows:

function Header() {
    const [Title, changeTitle] = useTitle();
    return (
        <div onClick={() => changeTitle('new title')}>
          <Title />
        </div>
    )
}

But writinguseTitleThere was a problem with the code:

function TitleComponent({title}) {
    return <div>{title}</div>
}
function useTitle() {
    const [title, changeTitle] = useState('default title');
    useEffect(() => {
	changeTitle(title)
    }, [title])
    const Element = (TitleComponent, {title});
    return [, changeTitle];
}

This code directly reports an error and cannot even render it. If it were you, how should you modify this code?

Elements and Components

In fact, this is a very typical question of how to distinguish and use elements and components.

element

Let's look at React firstIntroduction to React elements in official documentation

Babel will translate JSX into a()Function call. The following two example codes are completely equivalent:

const element = <h1 className="greeting">Hello, world!</h1>;
const element = (
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

()Some checks will be performed in advance to help you write error-free code, but in fact it creates an object like this:

// Note: This is a simplified structureconst element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

These objects are called "React elements". They describe what you want to see on the screen.

You see, the React element actually refers to the JSX code we write every day. It will be escaped by Babel as a function call. The final result is an object describing the DOM structure, and its data structure is essentially a JS object.

In JSX, we can embed expressions, such as:

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

So if we want to use a React element, we should use embedded expressions:

const name = <span>Josh Perez</span>;
const element = <h1>Hello, {name}</h1>;

Components

What about the components? There are two types of components, function components and class components:

// Function componentsfunction Welcome(props) {
  return &lt;h1&gt;Hello, {}&lt;/h1&gt;;
}
// class componentclass Welcome extends  {
  render() {
    return &lt;h1&gt;Hello, {}&lt;/h1&gt;;
  }
}

So how do you use components?

const element = <Welcome name="Sara" />;

For components, we want to call them in a way similar to HTML tags, and Babel will translate them into a function call

const element = (Welcome, {
  name: "Sara"
});

So you see, the data structure of a component is essentially a function or class. When you call it using the element label, the function or class will be executed and eventually return a React element.

How to solve the problem

Although these contents come from the official React documentation, if you can clearly understand the differences between React elements and components, you can already solve the problem at the beginning. There are at least two ways to solve it, one is to return the React element and the other is to return the React component

The first one we return the React element:

const root = (('root'));
function Header() {
    const [Title, changeTitle] = useTitle();
    // Because the React element is returned here, we use {} to embed the expression    return (
        &lt;div onClick={() =&gt; changeTitle('new title')}&gt;
          {Title}
        &lt;/div&gt;
    )
}
function TitleComponent({title}) {
    return &lt;div&gt;{title}&lt;/div&gt;
}
function useTitle() {
    const [title, changeTitle] = useState('default title');
    useEffect(() =&gt; {
	changeTitle(title)
    }, [title])
    // createElement returns React element    const Element = (TitleComponent, {title});
    return [Element, changeTitle];
}
(&lt;Header /&gt;);

The second type we return to the React component:

const root = (('root'));
function Header() {
    const [Title, changeTitle] = useTitle();
    // Because the return is a React component, we call it using the element tag    return (
        &lt;div onClick={() =&gt; changeTitle('new title')}&gt;
          &lt;Title /&gt;
        &lt;/div&gt;
    )
}
function TitleComponent({title}) {
    return &lt;div&gt;{title}&lt;/div&gt;
}
function useTitle() {
    const [title, changeTitle] = useState('default title');
    useEffect(() =&gt; {
	changeTitle(title)
    }, [title])
    // Here we build a function component    const returnComponent = () =&gt; {
    	return &lt;TitleComponent title={title} /&gt;
    }
    // Here we directly return the component    return [returnComponent, changeTitle];
}
(&lt;Header /&gt;);

Custom content

Sometimes we need to pass a custom content to the component.

For example, we implemented a Modal component, which has a definite button and a cancel button. However, in order to be more flexible, we provide a props property where the user can customize a component to pass into it. What the user provides, Modal will show what the Modal is equivalent to a container. So, how should we implement this function?

The first way to implement

The following is the first implementation method:

function Modal({content}) {
  return (
    &lt;div&gt;
      {content}
      &lt;button&gt;Sure&lt;/button&gt;
      &lt;button&gt;Cancel&lt;/button&gt;
    &lt;/div&gt;
  )
}
function CustomContent({text}) {
  return &lt;div&gt;{text}&lt;/div&gt;
}
&lt;Modal content={&lt;CustomContent text="content" /&gt;} /&gt;

Based on the previous knowledge, we can know thatcontentThe property is actually a React element, so the Modal component is used inside it.{}Make rendering.

The second way to implement it

But the first method does not always solve the needs. Sometimes, we may use the values ​​inside the component.

For example, a countdown componentTimer, still provides a propertycontent, a display style for custom time, time byTimerThe component is processed internally, and the display style is completely customized by the user. In this case, we can choose to pass in a component:

function Timer({content: Content}) {
    const [time, changeTime] = useState('0');
    useEffect(() => {
        setTimeout(() => {
            changeTime((new Date).toLocaleTimeString())
	}, 1000)
    }, [time])
    return (
        <div>
          <Content time={time} />
        </div>
    )
}
function CustomContent({time}) {
    return <div style={{border: '1px solid #ccc'}}>{time}</div>
}
<Timer content={CustomContent} />

In this example, we can seecontentThe property passes in a React component CustomContent, and the CustomContent component will be passed in the time property. We are developing the CustomContent component based on this convention.

Inside the Timer component, because the component is passed in, it is used.<Content time={time}/>rendering.

The third way to implement it

When facing the needs of the second implementation method, in addition to the above implementation method, there is another one calledrender propsThe trick is more common than the second method. Let's still take the Timer component as an example:

function Timer({renderContent}) {
    const [time, changeTime] = useState('0');
    useEffect(() =&gt; {
        setTimeout(() =&gt; {
            changeTime((new Date).toLocaleTimeString())
	}, 1000)
    }, [time])
  // The renderContent function passed in is called directly here    return (
        &lt;div&gt;
          {renderContent(time)}
        &lt;/div&gt;
    )
}
function CustomContent({time}) {
    return &lt;div style={{border: '1px solid #ccc'}}&gt;{time}&lt;/div&gt;
}
(&lt;Timer renderContent={(time) =&gt; {
    return &lt;CustomContent time={time} /&gt;
}} /&gt;);

Given that what we pass in is a function, wecontentChange the attribute name torenderContent, in fact, it can be called anything.

renderContentA function is passed in, which receivestimeAs an argument, a React element is returned, and inTimerInternally, we directly execute the renderContent function and pass in the internally processed time parameters, thereby realizing that users can customize rendering content using the internal values ​​of the component.

To put it more, in addition to put it in the attributes, we can also put it in children, it is the same:

function Timer({children}) {
  	// ...
    return (
        <div>
          {children(time)}
        </div>
    )
}
<Timer>
  {(time) => {
    return <CustomContent time={time} />
  }}
</Timer>

We can choose the appropriate incoming method depending on the situation.

React Series

React's createElement source code interpretation

The above is a detailed explanation of the examples of the difference between React elements and components. For more information on the differences between React elements, please pay attention to my other related articles!