DEV Community

nakzyu
nakzyu

Posted on

Common mistakes when using React - Why the screen value does not change

I guarantee that 99% of people who are new to React have been puzzled by the following phenomenon.

const Counter = () => {
  let counter = 0;
  return <button onClick={() => counter++}>{counter}</button>;
};
Enter fullscreen mode Exit fullscreen mode

Why isn't the counter going up on the screen when you press the button?

Do you know why counter doesn't go up when you press the button after you have used useState?

So, how does React work fundamentally?

/* html */
<body>
  <div id="app"></div>
</body>;

/* js */
const $app = document.getElementById("app");
const jsx = <div>Hello</div>;
ReactDom.render(jsx, $app);
Enter fullscreen mode Exit fullscreen mode

After receiving the JSX.Element, it is parsed into a pure HtmlElement, specified a specific HtmlElement, and renders the parsed value <div>Hello</div> under that HtmlElement.

To help understand it, here's what it looks like in Vanilla JS:

const $app = document.getElementById("app");
const $divElement = doucment.createElement("div");
$divElement.innerText = "Hello";
$app.appendChild($divElement);
Enter fullscreen mode Exit fullscreen mode

Getting back on track, what will happen if you run the following code?

const $app = document.getElementById("app");
let jsx = <div>Hello</div>;
ReactDom.render(jsx, $app);
setTimeout(() => {
  jsx = <div>Nice to meet you</div>;
}, 3000); // Changes the value of jsx to <div>Nice to meet you</div> after 3 seconds
Enter fullscreen mode Exit fullscreen mode

The answer is that the text displayed on the screen does not change from "Hello" to "Nice to meet you." The reason is the same as the counter example we started with.

Because...

It's because we didn't call ReactDom.render() again!

const $app = document.getElementById("app");
let jsx = <div>Hello</div>;
ReactDom.render(jsx, $app);
setTimeout(() => {
  jsx = <div>Nice to meet you</div>; // Changes the value of jsx to <div>Nice to meet you</div>
  ReactDom.render(jsx, $app); // Applies the changed value under $app again.
}, 3000);
Enter fullscreen mode Exit fullscreen mode

If you call ReactDom.render() again in the timeout callback, the text on the screen will finally change to "Nice to meet you."

Now let's apply this to the counter example...

const Counter = () => {
  let counter = 0;
  return <button onClick={() => counter++}>{counter}</button>;
};
Enter fullscreen mode Exit fullscreen mode

How can we apply it here?

Are you struggling with how to apply ReactDom.Render?

We don't actually need to import the ReactDom.Render function here.

const Counter = () => {
  const [counter, setCounter] = useState(0);
  return (
    <button onClick={() => setCounter((prev) => prev + 1)}>{counter}</button>
  );
};
const $app = document.getElementById("app");
ReactDom.render(<Clicker />, $app);
Enter fullscreen mode Exit fullscreen mode

The setState function of the array returned by useState (in this case, setCounter) calls ReactDom.Render internally every time it is executed.

In summary...

The reason why the counter doesn't increment when the button is clicked in the initial Counter example is simple.

It's because we haven't actually manipulated the HtmlElement.

We need to parse the JSXElement into an actual HtmlElement using ReactDom.render and then render it on the DOM to see the value change on the screen.

Top comments (0)