How to use useState Hook with objects in React?

Jul 08, 2025Leave a message

Hey there! I'm a supplier of various hooks, including Pegboard Hooks and Slatwall Hooks. But today, I'm gonna switch gears a bit and talk about something in the React world - how to use the useState Hook with objects in React.

Pegboard Hooks0153_1

So, if you're into React development, you've probably come across the useState Hook. It's one of the most basic yet super useful Hooks in React. It allows you to add state to functional components, which was mainly the job of class components before Hooks came along.

Let's start with a quick refresher on what the useState Hook is. In a nutshell, useState is a function that takes an initial state value as an argument and returns an array with two elements. The first element is the current state value, and the second one is a function that you can use to update that state.

import React, { useState } from'react';

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

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

In this simple example, we're using useState to manage a numeric state. But what if we want to manage an object state? That's where things get a bit more interesting.

Using useState with Objects

When you want to use useState with an object, you just pass an object as the initial state value. Let's say we're building a form where we want to manage the input values as an object.

import React, { useState } from'react';

function Form() {
    const [formData, setFormData] = useState({
        name: '',
        email: ''
    });

    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData(prevFormData => ({
            ...prevFormData,
            [name]: value
        }));
    };

    return (
        <form>
            <input
                type="text"
                name="name"
                placeholder="Name"
                onChange={handleChange}
            />
            <input
                type="email"
                name="email"
                placeholder="Email"
                onChange={handleChange}
            />
            <button type="submit">Submit</button>
        </form>
    );
}

In this example, we initialize the formData state as an object with name and email properties. When the user types in the input fields, the handleChange function is called. Inside this function, we use the spread operator (...) to create a new object that includes all the previous properties of formData and then update the specific property based on the input's name attribute.

Why the Spread Operator?

You might be wondering why we're using the spread operator (...) in the setFormData function. Well, React's state updates are shallow. That means when you update an object state, React doesn't automatically merge the new object with the old one. If you just do setFormData({ [name]: value }), you'll end up overwriting the entire formData object and losing the other properties.

By using the spread operator, we're creating a new object that has all the properties of the previous state object, and then we're updating only the property that needs to be changed.

Updating Nested Objects

What if your object has nested objects? For example, let's say our formData also has an address object.

import React, { useState } from'react';

function Form() {
    const [formData, setFormData] = useState({
        name: '',
        email: '',
        address: {
            street: '',
            city: ''
        }
    });

    const handleChange = (e) => {
        const { name, value } = e.target;
        setFormData(prevFormData => {
            if (name.includes('address.')) {
                const [, nestedKey] = name.split('.');
                return {
                    ...prevFormData,
                    address: {
                        ...prevFormData.address,
                        [nestedKey]: value
                    }
                };
            }
            return {
                ...prevFormData,
                [name]: value
            };
        });
    };

    return (
        <form>
            <input
                type="text"
                name="name"
                placeholder="Name"
                onChange={handleChange}
            />
            <input
                type="email"
                name="email"
                placeholder="Email"
                onChange={handleChange}
            />
            <input
                type="text"
                name="address.street"
                placeholder="Street"
                onChange={handleChange}
            />
            <input
                type="text"
                name="address.city"
                placeholder="City"
                onChange={handleChange}
            />
            <button type="submit">Submit</button>
        </form>
    );
}

Here, we're checking if the input's name attribute includes address.. If it does, we're updating the nested address object using the spread operator again.

Common Mistakes and How to Avoid Them

One common mistake when using useState with objects is directly mutating the state object. Remember, React relies on immutability to detect state changes. If you directly modify the state object, React might not re - render the component correctly.

// Bad practice
setFormData(formData.name = 'New Name');

// Good practice
setFormData(prevFormData => ({
    ...prevFormData,
    name: 'New Name'
}));

Another mistake is not using the functional form of the state update function when you need to update the state based on the previous state. If you don't use the functional form, you might end up with stale state values, especially in asynchronous operations.

// Bad practice
setFormData({
    ...formData,
    name: 'New Name'
});

// Good practice
setFormData(prevFormData => ({
    ...prevFormData,
    name: 'New Name'
}));

Conclusion

Using useState with objects in React is a powerful way to manage complex state in functional components. By understanding how to use the spread operator and the functional form of the state update function, you can effectively manage object states and avoid common pitfalls.

If you're in the market for high - quality hooks, whether it's Pegboard Hooks or Slatwall Hooks, I'm here to help. Feel free to reach out for more information and to start a procurement discussion.

References

  • React official documentation
  • React Hooks API reference