Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/content/learn/tutorial-tic-tac-toe.md
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,7 @@ The DOM `<button>` element's `onClick` attribute has a special meaning to React

Note how in `handleClick`, you call `.slice()` to create a copy of the `squares` array instead of modifying the existing array. To explain why, we need to discuss immutability and why immutability is important to learn.

There are generally two approaches to changing data. The first approach is to _mutate_ the data by directly changing the data's values. The second approach is to replace the data with a new copy which has the desired changes. Here is what it would look like if you mutated the `squares` array:
In React, _mutating_ state directly doesn’t trigger re-renders because React cannot detect changes to the same object reference. To update state, you must replace the data with a new copy that has the desired changes. This _immutable_ update ensures React knows the state has changed and re-renders your component. Here is what it would look like if you mutated the `squares` array:

```jsx
const squares = [null, null, null, null, null, null, null, null, null];
Expand All @@ -1355,6 +1355,12 @@ const nextSquares = ['X', null, null, null, null, null, null, null, null];

The result is the same but by not mutating (changing the underlying data) directly, you gain several benefits.

<Note>

__Mutating state__ directly doesn't trigger re-renders. When you mutate an object or array in place, React cannot detect the change because the reference remains the same and due to that your component will not re-render.

</Note>

Immutability makes complex features much easier to implement. Later in this tutorial, you will implement a "time travel" feature that lets you review the game's history and "jump back" to past moves. This functionality isn't specific to games--an ability to undo and redo certain actions is a common requirement for apps. Avoiding direct data mutation lets you keep previous versions of the data intact, and reuse them later.

There is also another benefit of immutability. By default, all child components re-render automatically when the state of a parent component changes. This includes even the child components that weren't affected by the change. Although re-rendering is not by itself noticeable to the user (you shouldn't actively try to avoid it!), you might want to skip re-rendering a part of the tree that clearly wasn't affected by it for performance reasons. Immutability makes it very cheap for components to compare whether their data has changed or not. You can learn more about how React chooses when to re-render a component in [the `memo` API reference](/reference/react/memo).
Expand Down
4 changes: 2 additions & 2 deletions src/content/learn/updating-arrays-in-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ Arrays are mutable in JavaScript, but you should treat them as immutable when yo

## Updating arrays without mutation {/*updating-arrays-without-mutation*/}

In JavaScript, arrays are just another kind of object. [Like with objects](/learn/updating-objects-in-state), **you should treat arrays in React state as read-only.** This means that you shouldn't reassign items inside an array like `arr[0] = 'bird'`, and you also shouldn't use methods that mutate the array, such as `push()` and `pop()`.
In JavaScript, arrays are just another kind of object. [Like with objects](/learn/updating-objects-in-state), **you should treat arrays in React state as read-only.** Although JavaScript arrays are technically mutable, mutating them directly __(for example, with `arr[0] = 'bird'` or methods like `push() and pop()`)__ will not trigger a re‑render because React cannot detect the change.

Instead, every time you want to update an array, you'll want to pass a *new* array to your state setting function. To do that, you can create a new array from the original array in your state by calling its non-mutating methods like `filter()` and `map()`. Then you can set your state to the resulting new array.
Instead, every time you want to update an array, you need to pass a *new* array to your __state setting function__. To do that, you can create a new array from the original array in your state by calling its non-mutating methods like `filter()` and `map()` or simply using spread operator `[ ... ]`. Then you can set your state to the resulting new array.

Here is a reference table of common array operations. When dealing with arrays inside React state, you will need to avoid the methods in the left column, and instead prefer the methods in the right column:

Expand Down
6 changes: 3 additions & 3 deletions src/content/learn/updating-objects-in-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Technically, it is possible to change the contents of _the object itself_. **Thi
position.x = 5;
```

However, although objects in React state are technically mutable, you should treat them **as if** they were immutable--like numbers, booleans, and strings. Instead of mutating them, you should always replace them.
However, objects are technically **mutable**, but mutating them directly will not trigger **re-renders** because React cannot detect the change. Instead, always create a new object with the desired updates and replace the state with that new copy (Immutate object).

## Treat state as read-only {/*treat-state-as-read-only*/}

Expand Down Expand Up @@ -104,7 +104,7 @@ onPointerMove={e => {
}}
```

This code modifies the object assigned to `position` from [the previous render.](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time) But without using the state setting function, React has no idea that object has changed. So React does not do anything in response. It's like trying to change the order after you've already eaten the meal. While mutating state can work in some cases, we don't recommend it. You should treat the state value you have access to in a render as read-only.
This code modifies the object assigned to `position` from [the previous render.](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time) But without using the state setting function, React cannot detect that the object has changed, so no **re-render** occurs. So React does not do anything in response. It's like trying to change the order after you've already eaten the meal. Mutating state directly is unreliable and should be avoided. In React, always treat state as read-only and use the setter function to replace it with a new object when making updates.

To actually [trigger a re-render](/learn/state-as-a-snapshot#setting-state-triggers-renders) in this case, **create a *new* object and pass it to the state setting function:**

Expand Down Expand Up @@ -804,7 +804,7 @@ There are a few reasons:
* **Requirement Changes:** Some application features, like implementing Undo/Redo, showing a history of changes, or letting the user reset a form to earlier values, are easier to do when nothing is mutated. This is because you can keep past copies of state in memory, and reuse them when appropriate. If you start with a mutative approach, features like this can be difficult to add later on.
* **Simpler Implementation:** Because React does not rely on mutation, it does not need to do anything special with your objects. It does not need to hijack their properties, always wrap them into Proxies, or do other work at initialization as many "reactive" solutions do. This is also why React lets you put any object into state--no matter how large--without additional performance or correctness pitfalls.

In practice, you can often "get away" with mutating state in React, but we strongly advise you not to do that so that you can use new React features developed with this approach in mind. Future contributors and perhaps even your future self will thank you!
In practice, **mutating** state fundamentally prevents _React_ from detecting a change and triggering a **re-render**. For this reason, we strongly advise you _never_ to mutate state. Following the immutability rule ensures your components are reliable and avoids hard-to-debug issues. Future contributors and perhaps even your future self will thank you!

</DeepDive>

Expand Down