Objects And React State Explained Simply

State can hold any kind of JavaScript value, including objects. Although it may be tempting, you should never change objects you hold in React state directly. Instead, when you update an object, you need to create a new one and then set the state to use that copy.

React Mutations Explained Simply

So far we’ve only been working with numbers, strings, and booleans. These kinds of JavaScript values are “immutable” and trigger re-renders that replace a value.

setNumber(3)

Now consider an object in state:

const [number, setNumber] = useState({ x: 0, y: 0 });

Technically, it is possible to change the contents of the object itself. This is called a mutation:

Changing state directly in React is one of the biggest no-no’s of React.

number.x = 5;

Although objects in React state are technically mutable, you should treat them as if they were immutable.

Why is modifying state directly bad?

The issue with modifying state directly is that you are performing action from the previous render.

React has no idea that the state has changed and therefore does not render the page again.

To set state correctly and trigger a re-render use the setNumber function.

One caveat to this rule is mutating fresh objects.

// This is bad
number.x = 2

// This is fine
const newNumber = {};
newNumber.x = 2;

setNuber(newNumber);

Spread syntax and React explained

Often times, you ill want to include existing data as part of a new object.

The most reliable way to mutate state is to create a new object and pass it to setNumber.

setNumber({
    numberOne: number.x,
    numberTwo: number.y
})

Instead of having to manually type out objects into setNumber, you can use the spread operator.

setNumber({
    ...number
});

An important caveat to spread syntax is that it is “shallow” and only copies things one level deep.

What is [e.target.name]?

You can also use array brackets inside objects to specify a property with dynamic name.

setNumber({
    ...number,
    [e.target.name]: e.target.value
})

Updating objects that are nested in React

Sometimes state can be tricky when objects become nested like this:

const [person, setPerson] = useState({
  name: "teddy smith",
  location: {
    city: "Charlotte",
    state: "North Carolina"
});

If you want to read state, that’s easy:

console.log(person.location.state);
// outputs "North Carolina"

But updating the state will be difficult and in order to change state, you will need to produce a new object

setPerson({
    ...person,
    location: {
        ...person.location,
        city: "Dallas"
    }
})

The easiest way to update a nested object stored is via shallow copy and the spread operator.

Updating nested objects In React

Let’s say we have our previous object:

const [person, setPerson] = useState({
  name: "teddy smith",
  location: {
    city: "Charlotte",
    state: "North Carolina"
});

To update via spread syntax we can do:

setPerson(prevPerson => ({
    ...prevPerson,
    location: {
        ....prevPerson.location,
        state: "Dallas"
    }
}))

Leave a Reply

Your email address will not be published. Required fields are marked *