A Beginner’s Explanation of State in React

Shalveena Rohde
6 min readSep 30, 2021

I just started learning React. It’s blown my mind. In so many ways.

Learning React started easy: write some HTML looking code. React does some magic under the hood to change it into code that the browser can read, adds it to the DOM and voilà! you can see it on the browser.

Then came props. We pass ‘arguments’ into React components (which are just functions) by adding attributes to the component when it is ‘called’. Phew. That took me a while to get my head around.

And then…..states. Need I say more?

I will try to explain what I understand of the state hook and how it works in this (̶h̶o̶p̶e̶f̶u̶l̶l̶y̶)̶ ̶s̶h̶o̶r̶t̶ article. It is not intended to be a comprehensive explanation, or even a 100% correct one. It’s an effort by a beginner to understand the mystery of state in React, and what better way to understand than to try to put it in writing and explain it!

Why do we need state and what does it do exactly?

I have this app, which displays some expenses on a page:

I want to make it so when I click the ugly “Change Title” button, something happens to the title of each expense (e.g “Toilet Paper”). So I add an onClick attribute on the button element and give it a click handler function.

Whenever I click on “Change Title”, the click handler function should update the title to “Updated”.

But it does not! Why?

Because this ExpenseItem component is a function. It is ‘called’ when we use it:

<ExpenseItem title={props.items[0].title}>

When we call the component, React/JS reads each line of the component, the component returns the JSX code, which React changes into browser-readable code and then renders. Once that process is done, the result is rendered and it’s finished. When I then click on the “Change Title” button, the clickHandler function that was attached triggers, and it changes the title variable as instructed, but nothing changes on the browser because the component has already been rendered and is not re-read just because I clicked on a button.

We need a way to tell React to re-render it. And that is where state comes in.

How do we use state?

In order to use state, we need to import the useState function from react:

import { useState } from "react";

Then, we need to call useState. We pass to it the initial value of the variable whose state we want to monitor. Put another way, we pass it the initial value, which will be changed later and we want React to be able to pick up on that change.

It returns an array with two elements. The first element is the variable itself (the “state variable”); this is the variable whose state we are monitoring. The second element is a function that updates the state of the state variable.

In my example, I need to pass props.title into the useState function. That is because that’s the initial value of the title variable (which is the variable that will be changed later). I then use destructuring to create two variables, the first of which is set to the first element of the array returned by useState and the second is set to the second element:

Now, in my clickHandler function, I can call the setTitle function, which will update the title variable to “Updated”:

So now when I click the ugly “Change Title” button on any instance of the ExpenseItem element, the clickHandler function is called, which calls setTitle, and the title changes (for example, from “Toilet Paper” to “Updated”):

Ta-da, we have managed to get React to re-render the component with the new title.

But if you’re like me, you might be wondering….how does that work? Well, let me try to explain.

How does this all work?

When I click on the “Change Title” button, it fires the clickHandler function. That function calls the setTitle function. The setTitle function changes the state of the title variable and tells React to run through the code in this component again. So React starts going through the component again. When React encounters the first line (const [title, setTitle] = useState(props.title)), it knows not to re-set the state of title to props.title again. My guess is that React keeps track of when useState was first called, and what the initial state and subsequent states of title were, and is smart enough to remember that (magic!).

It continues reading the rest of the code and then it compares the returned JSX to the previous copy, and if there are any changes (like the title variable being changed to “updated”), it changes those parts on the DOM and renders it.

But I noticed an odd thing going on. If you look closely, you will see the clickHandler function has a second line in it — it logs the title variable to the console:

However, when I clicked the “Change Title” button on the first expense and triggered the above function, what was logged to the console was not “Updated” (which is what I expected), but “Toilet Paper” instead. What the? What is happening here? Shouldn’t the title be changed to “Updated”? Well, it was changed to Updated in the app, but not on the console.

Here, I clicked “Change Title” on the first expense once. It used to be called “Toilet Paper” but is now “Updated”. Hwoever, the title still appears as “Toilet Paper” in the console.

Why is this happening? To figure this out, I went back to my code and considered it again line-by-line. With the help of Google and StackOverflow, this is what I understood to be happening:

When the setTitle function is triggered, it causes React to go back to the beginning of the component function and re-render any changes. However, the setTitle function is asynchronous, so it doesn’t start running until the rest of the code in the clickHandler function is executed. That means that the next line (console.log(title)) will be executed, but with the old value of title. React will then go back to the beginning of the ExpenseItem component and will re-render the JSX part with the new value of title. This is why we see “Updated” as the title in the app, but “Toilet Paper” as the output in the console!
But now the value of title has been changed to “Updated” by setTitle, so the next time we click on “Change Title”, guess what will be logged to the console? That’s right — “Updated”, not “Toilet Paper”.

Here, you can see that when I clicked on “Change Title” a second time, the output logged to the console changed to “Updated”.

--

--

Shalveena Rohde

From lawyer to software developer. Learning to code 🤓 and exploring the world of technology.