Why do we need useState in functional React
If you have used React before, you might know about React's functional components. You might have also came across useState. So what exactly is it and why do we need it?
Let's take a look at the following example.
import React, { useState } from "react";import ReactDOM from "react-dom";const App = () => {let counter = 0;const increment = () => {counter += 1;console.log(counter);};return (<div><p>nonUseStateCounter: {counter}</p><button onClick={increment}>Increment</button></div>);};
Now if we click the increment button twice, you can see that the counter
is updated correctly via the console. However, the UI is never updated with the new counter
value. Why is that?
It is because nothing has triggered the component to re-render. How do we know this?
Because if the component re-renders, it will re-run the App
function, causing counter
to be reset back to 0
. You can also test this by console.log
anything before the return
.
const App = () => {console.log("render");let counter = 0;const increment = () => {counter += 1;console.log(counter);};return (<div><p>nonUseStateCounter: {counter}</p><button onClick={increment}>Increment</button></div>);};
This is why we need to use useState
because useState
can trigger re-render when the associated state
changes. Now let's combine both useState
and non-useState
to demonstrate the difference.
const App = () => {console.log("render");let [useStateCounter, setUseStateCounter] = useState(0);let counter = 0;const increment = () => {counter += 1;setUseStateCounter((prevCounter) => {const newCounter = prevCounter + 1;console.log(`useStateCounter: ${newCounter}`);return newCounter;});console.log(`counter: ${counter}`);};return (<div><p>useStateCounter: {useStateCounter}</p><p>nonUseStateCounter: {counter}</p><button onClick={increment}>Increment</button></div>);};
As you can see, useStateCounter
was updated correctly and is responsible for causing the App
component to re-render. We can tell the re-render is happening because render
is outputted every time we click the button. Counter
also stays as 1
because the re-render is causing the counter
to be re-declared and re-initialized to 0
.
This is precisely why you should use useState
for persist states across component re-renders.