DEV Community

Lucas Lachance
Lucas Lachance

Posted on

React Components - just a function that returns html

Let me make a grossly oversimplified statement that can help beginners understand React without diving too deeply into things like the "render loop" and the "shadow dom". If you just want to get the very basics of React components please read on. If you understand React internals, you should probably skip this for your own sanity.

The statement is :

A React Component is simply a function that returns HTML.

This oversimplification is important to understand so many things in React, I think it's a mantra that should be integrated by any beginner. So let's repeat again :

A React Component is simply a function that returns HTML.

Let's take for example this extremely simple React app which is a button with a counter:

import { useState } from 'react'

function App() {
  const [count, setCount] = useState(0)

  return (
    <button onClick={() => setCount((count) => count + 1)}>
      count is {count}
    </button>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

As you can see, App is a function. So that part of the statement is true as-is.

The second part of my statement is almost true : "it returns HTML" is technically false, because in fact there's a bunch of things that happens with the JSX ("almost html") returned by the component. But if we imagine for a second this is just HTML, then you can just think : this html is being put inside the webpage.

Is that simple enough? Good! I knew you would get it.

I'll call the return of a component JSX from now on because I've triggered enough people already.

But there's a 3rd part of the sentence that I omitted until now. David's secret chord as it were, which will definitely please the Lord.

A React Component is simply a function that runs every time its state or props change which returns JSX.

This new part explains exactly how React is "reactive", the core of its idea. When the state changes, the component renders again. That means, in simple terms, that the function runs again, and returns updated JSX.

This means that when setCount is called, the component function runs again, and this time, const [count, setCount] = useState(0); is going to ignore the default 0 value, and use the new state value instead. Which is why when it reaches the JSX, that value of count is put in the JSX, and that then goes to update the webpage.

So why does this matter?

The entire reason I wrote this short article is to explain one thing : "state updates are asynchronous". It's a common misunderstanding of React. Let's change the example code for the counter a little bit to demonstrate:

import { useState } from 'react'

function App() {
  const [count, setCount] = useState(0)

  const handleClick = () => {
    console.log(count);  
    setCount(count + 1);
    console.log(count);
  }
  return (
    <button onClick={handleClick}>
      count is {count}
    </button>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

So what's going to happen here? What will be the output of the console.log before and what will it be after?

If you said "0, then 1" on the first click... you forgot something extremely basic about javascript: You defined count with CONST. How would the value possibly change on a const??? So the answer is, they're both going to be 0. Then they're both going to be 1.

So how do you get the new value of a state within a function in your component? Well, simply, you don't. Rather than doing setCount(count + 1) what you do instead is const newCount = count + 1 and then you can console.log(newcount) and also setCount(newCount).

And what if you are doing some complex operation in the state and you can't do it outside because it's a functional setstate? In that case, you can rely on the new state via a useEffect:

import { useEffect, useState } from 'react'

function App() {
  const [count, setCount] = useState(0)

  const handleClick = () => { 
    setCount(count + 1);
  }

  useEffect(() => {
    console.log("new count value : ", count);
  , [count]);

  return (
    <button onClick={handleClick}>
      count is {count}
    </button>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Since the change in state triggers the component to render again and run the function, useEffect will be checked. And since it has a dependency on the count state which changed, it'll execute the body of the useEffect, and log the change!

Hopefully this clarifies the very basic idea:

A React Component is only a function that runs when its state or props change, and returns JSX.

Top comments (0)