Why is my useState hook not working properly?

İbrahim BABAL
2 min readJan 22, 2023

--

Wrong way to use useState hook

React’s useState hook is a powerful tool for managing component state, but it's important to understand the correct way to use it in order to avoid bugs and unexpected behavior. One common mistake is updating the properties of an object in state directly, rather than creating a new copy of the state and updating it.

The Problem

Consider the following example:

import { useState } from 'react';

function MyComponent() {
const [user, setUser] = useState({ name: 'John', age: 30 });
const handleClick = () => {
// WRONG: This will NOT trigger a re-render
user.age += 1;
setUser(user);
};
return (
<>
<div>Name: {user.name}</div>
<div>Age: {user.age}</div>
<button onClick={handleClick}>Increment Age</button>
</>
);
}

In this example, when the button is clicked, the handleClick function is supposed to increment the user's age by 1. However, because the code is directly modifying the user object's properties, React will not recognize that the state has changed and therefore will not trigger a re-render.

The Solution

The correct way to update an object’s properties in a useState hook is to create a new object and spread the existing state into it, then update the desired property, and call setState with that new object:

import { useState } from 'react';

function MyComponent() {
const [user, setUser] = useState({ name: 'John', age: 30 });
const handleClick = () => {
// CORRECT: This will trigger a re-render
setUser({...user, age: user.age + 1 });
};
return (
<>
<div>Name: {user.name}</div>
<div>Age: {user.age}</div>
<button onClick={handleClick}>Increment Age</button>
</>
);
}

Another way to update an object’s properties would be to use the callback form of setState, passing in the previous state and returning the new state:

import { useState } from 'react';

function MyComponent() {
const [user, setUser] = useState({ name: 'John', age: 30 });
const handleClick = () => {
// CORRECT: This will trigger a re-render
setUser(prevUser => {
return {...prevUser, age: prevUser.age + 1 }
});
};
return (
<>
<div>Name: {user.name}</div>
<div>Age: {user.age}</div>
<button onClick={handleClick}>Increment Age</button>
</>
);
}

Conclusion

It’s very important to keep in mind that when using the useState hook, you should never modify the state directly. Instead, you should create a new copy of the state and update it accordingly in order to trigger a re-render

--

--