The useState Hook: A Deep Dive into React State Management #2

The Atypical Developer
4 min readDec 20, 2022

--

In the previous article <link> you have learned how to set up your first React environment and run your app using CRA.

useState is a hook in React that allows you to add state to functional components. It returns a pair of values: the current state and a function that can be used to update the state. Here's an example of how you might use useState to add a piece of state called message to a functional component:

import React, { useState } from 'react';

function MyComponent() {
const [message, setMessage] = useState('Hello World');

return (
<div>
<p>{message}</p>
<button onClick={() => setMessage('Hello from the button!')}>
Update message
</button>
</div>
);
}

In this example, message is the current state value, and setMessage is a function that can be used to update the value of message. As an initial state we are using ‘Hello World’ string, although the initial state does not need to be defined, you can use type instead (string, bool, array etc.). So if we we’re going to set the type for messageit would be just useState('').

When the button is clicked, the setMessage function is called with the new value for message, which updates the state and causes the component to re-render with the new value.

It’s important to note that useState should be called inside the body of a functional component, not in the top-level scope or in any other part of the code.

useState caveats

  • when using useState is that the state update may not be applied immediately. This can be a problem if you're relying on the updated state value in the same function or block of code where you're calling the state update function.
  • For example, consider the following code:
const [count, setCount] = useState(0);

function increment() {
setCount(count + 1);
console.log(count); // Logs 0, not 1
}

In this example, the increment function increments the value of count by 1, but the state update may not be applied immediately. This means that the console.log statement will log the old value of count, not the updated value.

To work around this problem, you can use the second argument to the setState function, which is a callback that will be executed after the state update is applied. For example:

function increment() {
setCount(count + 1, () => {
console.log(count); // Logs the updated value of count
});
}

Alternatively, you can use the useEffect hook to perform an action after the state update is applied. For example:

useEffect(() => {
console.log(count); // Logs the updated value of count
}, [count]);
  • The state returned by useState is always a single value. If you need to store multiple values in state, you can use an object or an array to hold the values, and spread operator to update them. For example:
const [state, setState] = useState({ count: 0, message: 'Hello World' });

setState({ ...state, count: state.count + 1 })
console.log(state) // count: 1, message: 'Hello World'

If you were going only to update the count without copying the previous state, then the message state would get removed.

setState({ count: state.count + 1 })
console.log(state) // count: 1
  • useStateonly works with simple values (numbers, strings, booleans, etc.). If you need to store more complex values in state (such as objects or arrays), you should be careful not to modify them directly, because this can cause unexpected behavior. Instead, you should create a new copy of the value and update the state with the new copy. For example:
const [items, setItems] = useState([1, 2, 3]);

const newItems = [...items, 4];
setItems(newItems)
console.log(items) // [1,2,3,4]

And without the spread operator:

const [items, setItems] = useState([1, 2, 3]);

const newItems = [4];
setItems(newItems)
console.log(items) // [4]
  • useStateshould only be used for values that change within the component. If you need to store values that come from outside the component (such as props or context), you should use the useEffect hook to update the state when the values change. The useEffect hook is going to be covered in the next article!

Practice task

And now it’s time to better remember the collected information, for this purpose I have created a very simple and short task that will help you consolidate knowledge in the field of useState.

  1. In your repo, create functional component called Counter. Open the src/App.js file and import newly created component and the useState hook from the react package.
  2. In Counter component, call the useState hook you can call the values countand setCount . The initial value of count should be 0.
  3. In the JSX, display the current value of count and add an onClick handler to the button that increments the value of count using the updater function returned by useState.
  4. If that was too easy, add two more handlers to your Counter . The first one to decrement the current countvalue, and the second to reset the count value to the initial state.

Here’s what the Counter component should look like (basic):

import React, { useState } from 'react';

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

return (
<div>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<p>Count: {count}</p>
</div>
);

Bonus:

import React, { useState } from 'react';

const INIT_STATE = 0;
function Counter() {
const [count, setCount] = useState(INIT_STATE);

return (
<div>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<button onClick={() => setCount(count - 1)}>
Decrement
</button>
<button onClick={() => setCount(INIT_STATE)}>
Reset
</button>
<p>Count: {count}</p>
</div>
);

I hope it was easy for you to understand how the useStateworks. In the next article I will cover the useEffecthook.

--

--

No responses yet