diff --git a/src/content/learn/updating-arrays-in-state.md b/src/content/learn/updating-arrays-in-state.md
index 45c6b70dc..7c60a6f1a 100644
--- a/src/content/learn/updating-arrays-in-state.md
+++ b/src/content/learn/updating-arrays-in-state.md
@@ -1,52 +1,52 @@
---
-title: Updating Arrays in State
+title: state 内の配列の更新
---
-Arrays are mutable in JavaScript, but you should treat them as immutable when you store them in state. Just like with objects, when you want to update an array stored in state, you need to create a new one (or make a copy of an existing one), and then set state to use the new array.
+JavaScript の配列はミュータブル(mutable, 書き換え可能)なものですが、state に格納する場合はイミュータブル(immutable, 書き換え不能)として扱うべきです。オブジェクトの時と同様に、state に保存された配列を更新する場合は、新しい配列を作成して(または既存の配列をコピーして)、その新しい配列で state をセットする必要があります。
-- How to add, remove, or change items in an array in React state
-- How to update an object inside of an array
-- How to make array copying less repetitive with Immer
+- React の state 内にある配列に対し要素の追加、削除、変更を行う方法
+- 配列内にあるオブジェクトを更新する方法
+- Immer を使って配列コピーのためのコードの冗長さを緩和する方法
-## Updating arrays without mutation {/*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()`.
+JavaScript では、配列とは単なるオブジェクトの一種です。[オブジェクトのときと同様に](/learn/updating-objects-in-state)、**React の state 内にある配列は、読み取り専用として扱う必要があります**。これは、`arr[0] = 'bird'` のような形で配列内の要素に再代入を行ってはならず、`push()` や `pop()` のような配列をミューテーション(mutation, 書き換え)するメソッドを使ってもいけないということです。
-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.
+代わりに、配列を更新するたびに、新しい配列を state セッタ関数に渡す必要があります。これを実現するために、state の元の配列から `filter()` や `map()` といった書き換えを行わないメソッドを呼び出して新しい配列を作成できます。そして、結果として得られた新しい配列に state を設定することができます。
-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:
+以下は、一般的な配列操作の参照表です。React の state 内の配列を扱う際には、左の列にあるメソッドを避けて、右の列にあるメソッドを使用する必要があります :
-| | avoid (mutates the array) | prefer (returns a new array) |
+| | 使わない(配列を書き換える) | 使う(新しい配列を返す) |
| --------- | ----------------------------------- | ------------------------------------------------------------------- |
-| adding | `push`, `unshift` | `concat`, `[...arr]` spread syntax ([example](#adding-to-an-array)) |
-| removing | `pop`, `shift`, `splice` | `filter`, `slice` ([example](#removing-from-an-array)) |
-| replacing | `splice`, `arr[i] = ...` assignment | `map` ([example](#replacing-items-in-an-array)) |
-| sorting | `reverse`, `sort` | copy the array first ([example](#making-other-changes-to-an-array)) |
+| 追加 | `push`, `unshift` | `concat`, `[...arr]` spread syntax ([例](#adding-to-an-array)) |
+| 削除 | `pop`, `shift`, `splice` | `filter`, `slice` ([例](#removing-from-an-array)) |
+| 要素置換 | `splice`, `arr[i] = ...` 代入文 | `map` ([例](#replacing-items-in-an-array)) |
+| ソート | `reverse`, `sort` | 先に配列をコピー ([例](#making-other-changes-to-an-array)) |
-Alternatively, you can [use Immer](#write-concise-update-logic-with-immer) which lets you use methods from both columns.
+また、どちらの列のメソッドも使用できるようにしてくれる [Immer を使う](#write-concise-update-logic-with-immer)方法もあります。
-Unfortunately, [`slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) and [`splice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) are named similarly but are very different:
+残念ながら、[`slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) と [`splice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) は名前が似ているものの、非常に異なるものです。
-* `slice` lets you copy an array or a part of it.
-* `splice` **mutates** the array (to insert or delete items).
+* `slice` は配列や配列の一部をコピーします。
+* `splice` は(要素の挿入や削除という)配列の**ミューテーション**を行います。
-In React, you will be using `slice` (no `p`!) a lot more often because you don't want to mutate objects or arrays in state. [Updating Objects](/learn/updating-objects-in-state) explains what mutation is and why it's not recommended for state.
+React では、state 内のオブジェクトや配列を書き換えたくないため、 `slice`(`p` なし!)の方をより頻繁に使用します。[オブジェクトの更新](/learn/updating-objects-in-state)で、ミューテーションとは何で、それがなぜ state で推奨されないかについて説明されています。
-### Adding to an array {/*adding-to-an-array*/}
+### 配列に要素を追加 {/*adding-to-an-array*/}
-`push()` will mutate an array, which you don't want:
+`push()` は配列の書き換えを行います。これは避けるべきです。
@@ -88,7 +88,7 @@ button { margin-left: 5px; }
-Instead, create a *new* array which contains the existing items *and* a new item at the end. There are multiple ways to do this, but the easiest one is to use the `...` [array spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_array_literals) syntax:
+代わりに、既存の要素と新しい要素を含む*新しい*配列を作成します。これには複数の方法がありますが、もっとも簡単なのは `...` という[配列スプレッド構文](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_array_literals)を使用することです。
```js
setArtists( // Replace the state
@@ -99,7 +99,7 @@ setArtists( // Replace the state
);
```
-Now it works correctly:
+これで正しく動作します。
@@ -141,7 +141,7 @@ button { margin-left: 5px; }
-The array spread syntax also lets you prepend an item by placing it *before* the original `...artists`:
+配列スプレッド構文を使用すれば、元の `...artists` の*先頭*に要素を追加することもできます:
```js
setArtists([
@@ -150,11 +150,11 @@ setArtists([
]);
```
-In this way, spread can do the job of both `push()` by adding to the end of an array and `unshift()` by adding to the beginning of an array. Try it in the sandbox above!
+このように、スプレッド構文は、`push()` で配列の末尾に追加することと `unshift()` で配列の先頭に追加することの両方の役割を果たせます。上記のサンドボックスで試してみてください!
-### Removing from an array {/*removing-from-an-array*/}
+### 配列から要素を削除 {/*removing-from-an-array*/}
-The easiest way to remove an item from an array is to *filter it out*. In other words, you will produce a new array that will not contain that item. To do this, use the `filter` method, for example:
+配列から要素を削除する最も簡単な方法は、それを*フィルタリング*して取り除いた、新しい配列を作ることです。つまり、その要素を含まない新しい配列を生成します。これには `filter` メソッドを使用します。例えば:
@@ -198,7 +198,7 @@ export default function List() {
-Click the "Delete" button a few times, and look at its click handler.
+何度か "Delete" タンをクリックして動作を確認したら、クリックハンドラを見て見ましょう。
```js
setArtists(
@@ -206,13 +206,13 @@ setArtists(
);
```
-Here, `artists.filter(a => a.id !== artist.id)` means "create an array that consists of those `artists` whose IDs are different from `artist.id`". In other words, each artist's "Delete" button will filter _that_ artist out of the array, and then request a re-render with the resulting array. Note that `filter` does not modify the original array.
+ここで、`artists.filter(a => a.id !== artist.id)` というコードは「`artist.id` と異なる ID を持つ `artists` のみの配列を作成する」という意味です。言い換えると、各アーティストの "Delete" ボタンは、該当アーティストを配列からフィルタリングして取り除き、結果として得られる配列で再レンダーを要求します。`filter` は元の配列を書き換えないことに注意してください。
-### Transforming an array {/*transforming-an-array*/}
+### 配列の変換 {/*transforming-an-array*/}
-If you want to change some or all items of the array, you can use `map()` to create a **new** array. The function you will pass to `map` can decide what to do with each item, based on its data or its index (or both).
+配列の一部またはすべての要素を変更したい場合は、`map()` を使用して**新しい**配列を作成できます。`map` に渡す関数は、データやインデックス(またはその両方)に基づいて各要素に何をするかを決定できます。
-In this example, an array holds coordinates of two circles and a square. When you press the button, it moves only the circles down by 50 pixels. It does this by producing a new array of data using `map()`:
+この例では、配列に 2 つの円と 1 つの正方形の座標が含まれています。ボタンを押すと、円だけが 50 ピクセル下に移動します。これは、`map()` を使用して新しいデータの配列を作成することで行われます。
@@ -278,11 +278,11 @@ body { height: 300px; }
-### Replacing items in an array {/*replacing-items-in-an-array*/}
+### 配列内の要素の置換 {/*replacing-items-in-an-array*/}
-It is particularly common to want to replace one or more items in an array. Assignments like `arr[0] = 'bird'` are mutating the original array, so instead you'll want to use `map` for this as well.
+配列内の一部の要素だけを置き換えたい場合がよくあります。`arr[0] = 'bird'` のような代入は元の配列を書き換えるので、代わりにここでも `map` を使用する必要があります。
-To replace an item, create a new array with `map`. Inside your `map` call, you will receive the item index as the second argument. Use it to decide whether to return the original item (the first argument) or something else:
+要素を置き換えるには、`map` を使って新しい配列を作成します。`map` の呼び出し内では、第 2 引数として要素のインデックスを受け取ります。これを使用して、元の要素(第 1 引数)を返すか、他のものを返すかを決定します。
@@ -332,11 +332,11 @@ button { margin: 5px; }
-### Inserting into an array {/*inserting-into-an-array*/}
+### 配列への挿入 {/*inserting-into-an-array*/}
-Sometimes, you may want to insert an item at a particular position that's neither at the beginning nor at the end. To do this, you can use the `...` array spread syntax together with the `slice()` method. The `slice()` method lets you cut a "slice" of the array. To insert an item, you will create an array that spreads the slice _before_ the insertion point, then the new item, and then the rest of the original array.
+場合によっては、先頭でも終端でもない特定の位置に要素を挿入したいことがあります。これを行うには、`...` 配列スプレッド構文と `slice()` メソッドを使用できます。`slice()` メソッドを使用すると、配列の「スライス」を切り取ることができます。要素を挿入するには、挿入ポイントの前のスライスを展開した配列、新しい要素、元の配列の残りの部分を作成します。
-In this example, the Insert button always inserts at the index `1`:
+この例では、 "Insert" ボタンは常にインデックス `1` の場所に挿入を行います。
@@ -396,13 +396,13 @@ button { margin-left: 5px; }
-### Making other changes to an array {/*making-other-changes-to-an-array*/}
+### 配列へのその他の変更 {/*making-other-changes-to-an-array*/}
-There are some things you can't do with the spread syntax and non-mutating methods like `map()` and `filter()` alone. For example, you may want to reverse or sort an array. The JavaScript `reverse()` and `sort()` methods are mutating the original array, so you can't use them directly.
+スプレッド構文や、`map()`、`filter()` などの書き換えを行わないメソッドを使っているだけでは不可能なこともあります。例えば、配列を逆順にしたり、ソートしたりすることができません。JavaScript の `reverse()` や `sort()` メソッドは元の配列を書き換えるため、直接使うことはできません。
-**However, you can copy the array first, and then make changes to it.**
+**ただし、最初に配列をコピーしてから、そのコピーに変更を加えることはできます。**
-For example:
+例えば、次のようになります。
@@ -442,9 +442,9 @@ export default function List() {
-Here, you use the `[...list]` spread syntax to create a copy of the original array first. Now that you have a copy, you can use mutating methods like `nextList.reverse()` or `nextList.sort()`, or even assign individual items with `nextList[0] = "something"`.
+ここでは、`[...list]` スプレッド構文を使って、最初に元の配列のコピーを作成します。コピーができたら、`nextList.reverse()` や `nextList.sort()` などのミューテーション型のメソッドを使ったり、`nextList[0] = "something"` で個々の要素に代入したりすることができます。
-However, **even if you copy an array, you can't mutate existing items _inside_ of it directly.** This is because copying is shallow--the new array will contain the same items as the original one. So if you modify an object inside the copied array, you are mutating the existing state. For example, code like this is a problem.
+ただし、**配列をコピーしても、その中の既存のアイテムを直接変更することはできません**。これは、コピーが浅く (shallow) 行われるためです。新しい配列には、元の配列と同じ要素が含まれます。そのため、コピーされた配列内のオブジェクトを書き換えると、既存の state が破壊されます。例えば、このようなコードは問題があります。
```js
const nextList = [...list];
@@ -452,15 +452,15 @@ nextList[0].seen = true; // Problem: mutates list[0]
setList(nextList);
```
-Although `nextList` and `list` are two different arrays, **`nextList[0]` and `list[0]` point to the same object.** So by changing `nextList[0].seen`, you are also changing `list[0].seen`. This is a state mutation, which you should avoid! You can solve this issue in a similar way to [updating nested JavaScript objects](/learn/updating-objects-in-state#updating-a-nested-object)--by copying individual items you want to change instead of mutating them. Here's how.
+`nextList` と `list` は異なる 2 つの配列ですが、**`nextList[0]` と `list[0]` は同じオブジェクトを指しています**。そのため、`nextList[0].seen` を変更することで、`list[0].seen` も変更されます。これは state のミューテーションであり、避けるべきです! この問題は、[ネストされた JavaScript オブジェクトの更新](/learn/updating-objects-in-state#updating-a-nested-object)と同様の方法で解決できます。変更を加えたい個々の要素を、書き換える代わりにコピーするということです。以下で説明します。
-## Updating objects inside arrays {/*updating-objects-inside-arrays*/}
+## 配列内のオブジェクトを更新する {/*updating-objects-inside-arrays*/}
-Objects are not _really_ located "inside" arrays. They might appear to be "inside" in code, but each object in an array is a separate value, to which the array "points". This is why you need to be careful when changing nested fields like `list[0]`. Another person's artwork list may point to the same element of the array!
+オブジェクトは、*実際には*配列の「中に」あるわけではありません。コード中では「中に」あるように見えますが、配列内の各オブジェクトはそれぞれ独立した値であり、配列はそれらを「参照」しています。これが、`list[0]` のようなネストしたフィールドを変更する際に注意が必要な理由です。他の人のアートワークリストが、配列の同じ要素を指しているかもしれません!
-**When updating nested state, you need to create copies from the point where you want to update, and all the way up to the top level.** Let's see how this works.
+**ネストされた state を更新する際には、更新したい箇所からトップレベルまでのコピーを作成する必要があります**。どのように行うのか見てみましょう。
-In this example, two separate artwork lists have the same initial state. They are supposed to be isolated, but because of a mutation, their state is accidentally shared, and checking a box in one list affects the other list:
+この例では、2 つの別々のアートワークリストが同じ初期 state を持っています。これらは独立していることになっているのですが、ミューテーションが起きているため state が誤って共有され、一方のリストでボックスをチェックするともう一方のリストに影響してしまっています。
@@ -540,7 +540,7 @@ function ItemList({ artworks, onToggle }) {
-The problem is in code like this:
+問題はこのコードです。
```js
const myNextList = [...myList];
@@ -549,9 +549,9 @@ artwork.seen = nextSeen; // Problem: mutates an existing item
setMyList(myNextList);
```
-Although the `myNextList` array itself is new, the *items themselves* are the same as in the original `myList` array. So changing `artwork.seen` changes the *original* artwork item. That artwork item is also in `yourList`, which causes the bug. Bugs like this can be difficult to think about, but thankfully they disappear if you avoid mutating state.
+`myNextList` という配列自体は新しいものですが、個々の*要素そのもの*は元の `myList` 配列と同じです。そのため、`artwork.seen` を変更することで、*元の*アートワークも変更されます。そのアートワークは `yourList` 内にも存在するため、バグが発生します。このようなバグは理解するのが難しいことがありますが、幸いにも state のミューテーションさえ避けておけば、起こさずに済みます。
-**You can use `map` to substitute an old item with its updated version without mutation.**
+**ミューテーションをせずに、古い要素を更新された要素と置き換えるには、`map` を使用できます**。
```js
setMyList(myList.map(artwork => {
@@ -565,9 +565,9 @@ setMyList(myList.map(artwork => {
}));
```
-Here, `...` is the object spread syntax used to [create a copy of an object.](/learn/updating-objects-in-state#copying-objects-with-the-spread-syntax)
+ここで、`...` はオブジェクトのスプレッド構文であり、[オブジェクトのコピーを作成する](/learn/updating-objects-in-state#copying-objects-with-the-spread-syntax)ために使われます。
-With this approach, none of the existing state items are being mutated, and the bug is fixed:
+このアプローチでは、既存の state の要素を書き換えないため、バグは修正されています。
@@ -653,16 +653,16 @@ function ItemList({ artworks, onToggle }) {
-In general, **you should only mutate objects that you have just created.** If you were inserting a *new* artwork, you could mutate it, but if you're dealing with something that's already in state, you need to make a copy.
+一般的には、**作成したばかりのオブジェクト以外は書き換えてはいけません**。*新しい*アートワークを挿入する場合にその新しい要素を書き換えても構いませんが、state にすでに存在するものを扱う場合は、コピーを作成する必要があります。
-### Write concise update logic with Immer {/*write-concise-update-logic-with-immer*/}
+### Immer を使って簡潔な更新ロジックを書く {/*write-concise-update-logic-with-immer*/}
-Updating nested arrays without mutation can get a little bit repetitive. [Just as with objects](/learn/updating-objects-in-state#write-concise-update-logic-with-immer):
+配列がネストされている場合、書き換えなしで更新を行うコードは冗長になりがちです。[オブジェクトのときと同様](/learn/updating-objects-in-state#write-concise-update-logic-with-immer)ですが、
-- Generally, you shouldn't need to update state more than a couple of levels deep. If your state objects are very deep, you might want to [restructure them differently](/learn/choosing-the-state-structure#avoid-deeply-nested-state) so that they are flat.
-- If you don't want to change your state structure, you might prefer to use [Immer](https://github.com/immerjs/use-immer), which lets you write using the convenient but mutating syntax and takes care of producing the copies for you.
+- 一般的には、state を 2〜3 レベル以上深く更新する必要はないはずです。state オブジェクトが非常に深い場合は、[別の構造に再構成](/learn/choosing-the-state-structure#avoid-deeply-nested-state)してフラットにすることができます。
+- state 構造を変更したくない場合は、[Immer](https://github.com/immerjs/use-immer) を使用して、書きやすいミューテート型の構文で記述しつつコピーを生成することができます。
-Here is the Art Bucket List example rewritten with Immer:
+以下は、Immer を使用して書き直したアートワークリストの例です。
@@ -763,7 +763,7 @@ function ItemList({ artworks, onToggle }) {
-Note how with Immer, **mutation like `artwork.seen = nextSeen` is now okay:**
+Immer を使用することで **`artwork.seen = nextSeen` のような書き換えができるようになりました**。
```js
updateMyTodos(draft => {
@@ -772,17 +772,17 @@ updateMyTodos(draft => {
});
```
-This is because you're not mutating the _original_ state, but you're mutating a special `draft` object provided by Immer. Similarly, you can apply mutating methods like `push()` and `pop()` to the content of the `draft`.
+これが可能なのは、Immer から渡される特別な `draft` オブジェクトを書き換えているのであり、*元の* state は書き換えていないためです。同様に、`draft` の内容に対して `push()` や `pop()` などのミューテーション型のメソッドを使用することもできます。
-Behind the scenes, Immer always constructs the next state from scratch according to the changes that you've done to the `draft`. This keeps your event handlers very concise without ever mutating state.
+裏側では、Immer は 常に、`draft` に対して行った書き換え操作に基づいて、次の state をゼロから構築します。これにより、state を書き換えてしまう心配をせず、イベントハンドラを非常に簡潔に保つことができます。
-- You can put arrays into state, but you can't change them.
-- Instead of mutating an array, create a *new* version of it, and update the state to it.
-- You can use the `[...arr, newItem]` array spread syntax to create arrays with new items.
-- You can use `filter()` and `map()` to create new arrays with filtered or transformed items.
-- You can use Immer to keep your code concise.
+- 配列を state に入れることができるが、それを直接変更してはいけない。
+- 配列を変更する代わりに、*新しい*バージョンを作成し、state を更新する。
+- `[...arr, newItem]` という配列スプレッド構文を使用して、新しい項目を持つ配列を作成できる。
+- `filter()` や `map()` を使用して、フィルタリングされた、あるいは変換されたアイテムを含む新しい配列を作成できる。
+- Immer を使ってコードを簡潔に保つことができる。
@@ -790,9 +790,9 @@ Behind the scenes, Immer always constructs the next state from scratch according
-#### Update an item in the shopping cart {/*update-an-item-in-the-shopping-cart*/}
+#### ショッピングカートの商品を更新 {/*update-an-item-in-the-shopping-cart*/}
-Fill in the `handleIncreaseClick` logic so that pressing "+" increases the corresponding number:
+`handleIncreaseClick` のロジックを埋めて、"+" を押すことで対応する数字が増えるようにしてください。
@@ -850,7 +850,7 @@ button { margin: 5px; }
-You can use the `map` function to create a new array, and then use the `...` object spread syntax to create a copy of the changed object for the new array:
+`map` 関数を使って新しい配列を作成し、その中で `...` オブジェクトスプレッド構文を使って変更された商品に対応するオブジェクトのコピーを作成します:
@@ -917,9 +917,9 @@ button { margin: 5px; }
-#### Remove an item from the shopping cart {/*remove-an-item-from-the-shopping-cart*/}
+#### ショッピングカートから商品を削除 {/*remove-an-item-from-the-shopping-cart*/}
-This shopping cart has a working "+" button, but the "–" button doesn't do anything. You need to add an event handler to it so that pressing it decreases the `count` of the corresponding product. If you press "–" when the count is 1, the product should automatically get removed from the cart. Make sure it never shows 0.
+このショッピングカートでは "+" ボタンは機能していますが、"–" ボタンは何もしません。これに対応するイベントハンドラを追加して、押すことで対応する商品の `count` を減らすようにしてください。カウントが 1 の場合に "–" を押すと、商品が自動的にカートから削除されるようにしてください。0 と表示されないようにしてください。
@@ -989,7 +989,7 @@ button { margin: 5px; }
-You can first use `map` to produce a new array, and then `filter` to remove products with a `count` set to `0`:
+まず `map` を使って新しい配列を生成し、次に `filter` を使って `count` が `0` となっている商品を削除します。
@@ -1078,9 +1078,9 @@ button { margin: 5px; }
-#### Fix the mutations using non-mutative methods {/*fix-the-mutations-using-non-mutative-methods*/}
+#### ミューテーションを行わないように修正 {/*fix-the-mutations-using-non-mutative-methods*/}
-In this example, all of the event handlers in `App.js` use mutation. As a result, editing and deleting todos doesn't work. Rewrite `handleAddTodo`, `handleChangeTodo`, and `handleDeleteTodo` to use the non-mutative methods:
+この例では、`App.js` のすべてのイベントハンドラがミューテーションを行っています。そのため、todo アイテムの編集や削除が機能していません。`handleAddTodo`、`handleChangeTodo`、`handleDeleteTodo` を、ミューテーションを行わないメソッドを使って書き直してください。
@@ -1243,7 +1243,7 @@ ul, li { margin: 0; padding: 0; }
-In `handleAddTodo`, you can use the array spread syntax. In `handleChangeTodo`, you can create a new array with `map`. In `handleDeleteTodo`, you can create a new array with `filter`. Now the list works correctly:
+`handleAddTodo` では、配列のスプレッド構文が使えます。`handleChangeTodo` では、`map` で新しい配列を作成します。`handleDeleteTodo` では、`filter` で新しい配列を作成します。これでリストが正しく動作します。
@@ -1411,9 +1411,9 @@ ul, li { margin: 0; padding: 0; }
-#### Fix the mutations using Immer {/*fix-the-mutations-using-immer*/}
+#### Immer でミューテーションを修正 {/*fix-the-mutations-using-immer*/}
-This is the same example as in the previous challenge. This time, fix the mutations by using Immer. For your convenience, `useImmer` is already imported, so you need to change the `todos` state variable to use it.
+これは、ひとつ前のチャレンジと同じ例です。今回は、Immer を使用してミューテーションを修正します。`useImmer` はすでにインポートしてありますので、`todos` の state 変数をこれを使って更新してください。
@@ -1595,7 +1595,7 @@ ul, li { margin: 0; padding: 0; }
-With Immer, you can write code in the mutative fashion, as long as you're only mutating parts of the `draft` that Immer gives you. Here, all mutations are performed on the `draft` so the code works:
+Immer を使うと、Immer から渡される `draft` のみを書き換えている限りは、ミューテーション型のコードを書くことができます。ここでは、ミューテーションは `draft` に対してのみ行われているため、コードが機能します。
@@ -1781,9 +1781,9 @@ ul, li { margin: 0; padding: 0; }
-You can also mix and match the mutative and non-mutative approaches with Immer.
+Immer を使えば、ミューテーション型と非ミューテーション型のアプローチを混在させることもできます。
-For example, in this version `handleAddTodo` is implemented by mutating the Immer `draft`, while `handleChangeTodo` and `handleDeleteTodo` use the non-mutative `map` and `filter` methods:
+例えば、以下では `handleAddTodo` は Immer の `draft` を使ってミューテーション型で書かれていますが、`handleChangeTodo` と `handleDeleteTodo` は非ミューテーション型の `map` や `filter` メソッドで書かれています。
@@ -1966,7 +1966,7 @@ ul, li { margin: 0; padding: 0; }
-With Immer, you can pick the style that feels the most natural for each separate case.
+Immer を使うことで、個々のケースごとに最も自然に感じるスタイルを選ぶことができます。
diff --git a/src/content/learn/updating-objects-in-state.md b/src/content/learn/updating-objects-in-state.md
index 1e23c8d3d..54d57dd46 100644
--- a/src/content/learn/updating-objects-in-state.md
+++ b/src/content/learn/updating-objects-in-state.md
@@ -1,57 +1,57 @@
---
-title: Updating Objects in State
+title: state 内のオブジェクトの更新
---
-State can hold any kind of JavaScript value, including objects. But you shouldn't change objects that you hold in the React state directly. Instead, when you want to update an object, you need to create a new one (or make a copy of an existing one), and then set the state to use that copy.
+state にはどのような JavaScript の値でも保持することができます。これにはオブジェクトも含まれます。しかし、React の state に保持されたオブジェクトを直接書き換えるべきではありません。オブジェクトを更新したい場合、代わりに新しいオブジェクトを作成(または既存のもののコピーを作成)し、それを使って state をセットする必要があります。
-- How to correctly update an object in React state
-- How to update a nested object without mutating it
-- What immutability is, and how not to break it
-- How to make object copying less repetitive with Immer
+- React の state 内のオブジェクトを正しく更新する方法
+- ミューテートせずにネストされたオブジェクトを更新する方法
+- イミュータビリティとは何で、どのようにして遵守するのか
+- Immer を使ってオブジェクトコピーのためのコードの冗長さを緩和する方法
-## What's a mutation? {/*whats-a-mutation*/}
+## ミューテーションとは? {/*whats-a-mutation*/}
-You can store any kind of JavaScript value in state.
+state には、どのような JavaScript の値でも格納することができます。
```js
const [x, setX] = useState(0);
```
-So far you've been working with numbers, strings, and booleans. These kinds of JavaScript values are "immutable", meaning unchangeable or "read-only". You can trigger a re-render to _replace_ a value:
+これまでに扱ってきたのは、数値、文字列、および真偽値です。これらの種類の JavaScript 値は "イミュータブル"(不変, immutable)、つまり値が変わることがなく「読み取り専用」なものです。再レンダーをトリガするには値を*置き換え*ます。
```js
setX(5);
```
-The `x` state changed from `0` to `5`, but the _number `0` itself_ did not change. It's not possible to make any changes to the built-in primitive values like numbers, strings, and booleans in JavaScript.
+`x` という state の値は `0` から `5` に置き換わりましたが、*`0` という数字そのもの*が変化したわけではありません。JavaScript の数値、文字列、真偽値のような組み込みプリミティブの値そのものを変化させることは不可能です。
-Now consider an object in state:
+さて、state にオブジェクトが入っている場合を考えてみましょう。
```js
const [position, setPosition] = useState({ x: 0, y: 0 });
```
-Technically, it is possible to change the contents of _the object itself_. **This is called a mutation:**
+技術的には、*オブジェクト自体*の内容を書き換えることが可能です。**これをミューテーション (mutation) と呼びます**。
```js
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.
+ただし、React の state 内にあるオブジェクトは技術的にはミュータブル(mutable, 書き換え可能)であるとしても、数値、真偽値、文字列と同様に、イミュータブルなものであるかのように扱うべきです。書き換えをする代わりに、常に値の置き換えをするべきです。
-## Treat state as read-only {/*treat-state-as-read-only*/}
+## state を読み取り専用として扱う {/*treat-state-as-read-only*/}
-In other words, you should **treat any JavaScript object that you put into state as read-only.**
+言い換えると、**state として格納するすべての JavaScript オブジェクトは読み取り専用**として扱う必要があります。
-This example holds an object in state to represent the current pointer position. The red dot is supposed to move when you touch or move the cursor over the preview area. But the dot stays in the initial position:
+以下の例では、現在のポインタ位置を表すオブジェクトを state に保持しています。プレビュー領域でタッチしたりマウスカーソルを動かしたりすると、赤い点が動いて欲しいと思っています。しかし、点が初期位置から動きません:
@@ -94,7 +94,7 @@ body { margin: 0; padding: 0; height: 250px; }
-The problem is with this bit of code.
+問題は、このコードにあります。
```js
onPointerMove={e => {
@@ -103,9 +103,9 @@ 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.
+このコードは、[直近のレンダー](/learn/state-as-a-snapshot#rendering-takes-a-snapshot-in-time)で `position` に割り当てられたオブジェクトを書き換え、つまりミューテートしています。しかし、state セット関数が使用されないと、React はそのオブジェクトが変更されたことを認識できません。そのため、React は何の反応もしません。これは料理をすでに食べた後で注文を変更しようとするようなものです。state のミューテートは一部のケースでは機能することがありますが、おすすめしません。レンダー内でアクセスできる state 値は、読み取り専用として扱うべきです。
-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:**
+この場合、実際に[再レンダーをトリガする](/learn/state-as-a-snapshot#setting-state-triggers-renders)ためには、***新しい*オブジェクトを作成し、それを state セット関数に渡す必要があります。**
```js
onPointerMove={e => {
@@ -116,12 +116,12 @@ onPointerMove={e => {
}}
```
-With `setPosition`, you're telling React:
+`setPosition` を使うことで、React に次のことを伝えます。
-* Replace `position` with this new object
-* And render this component again
+* `position` をこの新しいオブジェクトに置き換えよ
+* そしてもう一度このコンポーネントをレンダーせよ
-Notice how the red dot now follows your pointer when you touch or hover over the preview area:
+プレビューエリアでタッチするかマウスホバーすることで、赤い点がポインタに追随するようになりましたね。
@@ -168,25 +168,25 @@ body { margin: 0; padding: 0; height: 250px; }
-#### Local mutation is fine {/*local-mutation-is-fine*/}
+#### ローカルミューテーションは問題なし {/*local-mutation-is-fine*/}
-Code like this is a problem because it modifies an *existing* object in state:
+以下のようなコードは、state の*既存の*オブジェクトを変更しているため、問題があります。
```js
position.x = e.clientX;
position.y = e.clientY;
```
-But code like this is **absolutely fine** because you're mutating a fresh object you have *just created*:
+しかし、以下のようなコードは**全く問題ありません**。なぜなら、*作成したばかりの*新しいオブジェクトを書き換えているからです。
```js
const nextPosition = {};
nextPosition.x = e.clientX;
nextPosition.y = e.clientY;
setPosition(nextPosition);
-````
+```
-In fact, it is completely equivalent to writing this:
+実際、これは以下のように書くことと全く同等です。
```js
setPosition({
@@ -195,15 +195,15 @@ setPosition({
});
```
-Mutation is only a problem when you change *existing* objects that are already in state. Mutating an object you've just created is okay because *no other code references it yet.* Changing it isn't going to accidentally impact something that depends on it. This is called a "local mutation". You can even do local mutation [while rendering.](/learn/keeping-components-pure#local-mutation-your-components-little-secret) Very convenient and completely okay!
+state として存在する*既存の*オブジェクトを変更する場合にのみ、ミューテーションは問題になります。作成したばかりのオブジェクトであれば*他のコードはまだそれを参照していない*ので、書き換えても問題ありません。それを書き換えてもそれに依存する何かに誤って影響を与えることはありません。これを "ローカルミューテーション (local mutation)" と呼びます。[レンダー中にも](/learn/keeping-components-pure#local-mutation-your-components-little-secret)ローカルミューテーションを行うことができます。とても便利で、全く問題ありません!
-
+
-## Copying objects with the spread syntax {/*copying-objects-with-the-spread-syntax*/}
+## スプレッド構文を使ったオブジェクトのコピー {/*copying-objects-with-the-spread-syntax*/}
-In the previous example, the `position` object is always created fresh from the current cursor position. But often, you will want to include *existing* data as a part of the new object you're creating. For example, you may want to update *only one* field in a form, but keep the previous values for all other fields.
+前の例では、`position` オブジェクトは現在のカーソル位置から常に新規作成されます。しかし、多くの場合、新しく作成するオブジェクトに*既存の*データも含めたいことがあります。例えば、フォームの *1 つの*フィールドだけを更新し、他のすべてのフィールドについては以前の値を保持したい、ということがあります。
-These input fields don't work because the `onChange` handlers mutate the state:
+以下の入力フィールドは、`onChange` ハンドラが state を書き換えているため、動作しません。
@@ -269,13 +269,13 @@ input { margin-left: 5px; margin-bottom: 5px; }
-For example, this line mutates the state from a past render:
+例えば、以下の行は過去のレンダーからの state を書き換えてしまっています。
```js
person.firstName = e.target.value;
```
-The reliable way to get the behavior you're looking for is to create a new object and pass it to `setPerson`. But here, you want to also **copy the existing data into it** because only one of the fields has changed:
+望んだ動作を得る確実な方法は、新しいオブジェクトを作成し、`setPerson` に渡すことです。しかし、ここではフィールドのうちの 1 つだけが変更されているため、**既存のデータもコピーしたい**でしょう。
```js
setPerson({
@@ -285,7 +285,7 @@ setPerson({
});
```
-You can use the `...` [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals) syntax so that you don't need to copy every property separately.
+`...` という[オブジェクトスプレッド](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#spread_in_object_literals)構文を使用することで、すべてのプロパティを個別にコピーする必要がなくなります。
```js
setPerson({
@@ -294,9 +294,9 @@ setPerson({
});
```
-Now the form works!
+これでフォームが機能します!
-Notice how you didn't declare a separate state variable for each input field. For large forms, keeping all data grouped in an object is very convenient--as long as you update it correctly!
+各入力フィールドに対して state 変数を別々に宣言していないことに注目してください。大きなフォームでは、すべてのデータをオブジェクトにまとめて保持することが非常に便利です。正しく更新さえしていれば!
@@ -371,13 +371,13 @@ input { margin-left: 5px; margin-bottom: 5px; }
-Note that the `...` spread syntax is "shallow"--it only copies things one level deep. This makes it fast, but it also means that if you want to update a nested property, you'll have to use it more than once.
+`...` スプレッド構文は「浅い (shallow)」ことに注意してください。これは 1 レベルの深さでのみコピーを行います。これは高速ですが、ネストされたプロパティを更新したい場合は、スプレッド構文を複数回使用する必要があるということでもあります。
-#### Using a single event handler for multiple fields {/*using-a-single-event-handler-for-multiple-fields*/}
+#### 複数のフィールドに単一のイベントハンドラを使う {/*using-a-single-event-handler-for-multiple-fields*/}
-You can also use the `[` and `]` braces inside your object definition to specify a property with dynamic name. Here is the same example, but with a single event handler instead of three different ones:
+オブジェクト定義内で `[` と `]` 括弧を使って、動的な名前のプロパティを指定することもできます。以下は上記と例ですが、3 つの異なるイベントハンドラの代わりに 1 つのイベントハンドラを使用しています。
@@ -441,13 +441,13 @@ input { margin-left: 5px; margin-bottom: 5px; }
-Here, `e.target.name` refers to the `name` property given to the `` DOM element.
+ここでは、`e.target.name` は、`` DOM 要素に与えられた `name` プロパティを指しています。
-## Updating a nested object {/*updating-a-nested-object*/}
+## ネストされたオブジェクトの更新 {/*updating-a-nested-object*/}
-Consider a nested object structure like this:
+以下のようなネストされたオブジェクト構造を考えてみましょう。
```js
const [person, setPerson] = useState({
@@ -460,13 +460,13 @@ const [person, setPerson] = useState({
});
```
-If you wanted to update `person.artwork.city`, it's clear how to do it with mutation:
+`person.artwork.city` を更新したい場合、ミューテーションで変更する方法は明らかです。
```js
person.artwork.city = 'New Delhi';
```
-But in React, you treat state as immutable! In order to change `city`, you would first need to produce the new `artwork` object (pre-populated with data from the previous one), and then produce the new `person` object which points at the new `artwork`:
+しかし、React では state をイミュータブルなものとして扱います! `city` を更新するためには、まず(既存のデータも含まれた)新しい `artwork` オブジェクトを生成する必要があります。そして、新しい `artwork` を含む新しい `person` オブジェクトを生成します。
```js
const nextArtwork = { ...person.artwork, city: 'New Delhi' };
@@ -474,7 +474,7 @@ const nextPerson = { ...person, artwork: nextArtwork };
setPerson(nextPerson);
```
-Or, written as a single function call:
+あるいは、単一の関数呼び出しとして記述する場合は以下のようになります。
```js
setPerson({
@@ -486,7 +486,7 @@ setPerson({
});
```
-This gets a bit wordy, but it works fine for many cases:
+これは少し冗長ですが、多くのケースでうまく機能します。
@@ -596,9 +596,9 @@ img { width: 200px; height: 200px; }
-#### Objects are not really nested {/*objects-are-not-really-nested*/}
+#### オブジェクトは実際にはネストされない {/*objects-are-not-really-nested*/}
-An object like this appears "nested" in code:
+このようなオブジェクトはコード内で「ネストされている」ように見えるでしょう:
```js
let obj = {
@@ -611,7 +611,7 @@ let obj = {
};
```
-However, "nesting" is an inaccurate way to think about how objects behave. When the code executes, there is no such thing as a "nested" object. You are really looking at two different objects:
+しかし、オブジェクトの振る舞いを考える場合、「ネスト」という考え方は正確ではありません。コードが実行されてしまえば「ネストされた」オブジェクトというものは存在しません。実際には、2 つの異なるオブジェクトを見ているだけです:
```js
let obj1 = {
@@ -626,7 +626,7 @@ let obj2 = {
};
```
-The `obj1` object is not "inside" `obj2`. For example, `obj3` could "point" at `obj1` too:
+`obj1` オブジェクトは `obj2` の「内部」にあるのではありません。例えば、`obj3` も `obj1` を「参照する」ことができます:
```js
let obj1 = {
@@ -646,13 +646,13 @@ let obj3 = {
};
```
-If you were to mutate `obj3.artwork.city`, it would affect both `obj2.artwork.city` and `obj1.city`. This is because `obj3.artwork`, `obj2.artwork`, and `obj1` are the same object. This is difficult to see when you think of objects as "nested". Instead, they are separate objects "pointing" at each other with properties.
+`obj3.artwork.city` を変更すると、`obj2.artwork.city` と `obj1.city` の両方に影響を与えます。これは、`obj3.artwork`、`obj2.artwork`、および `obj1` が同一のオブジェクトであるためです。これは、オブジェクトが「ネストされている」と考えると理解しにくくなります。そうではなく、これらはあくまで別々のオブジェクトであり、プロパティで互いを「参照している」のです。
-
+
-### Write concise update logic with Immer {/*write-concise-update-logic-with-immer*/}
+### Immer で簡潔な更新ロジックを書く {/*write-concise-update-logic-with-immer*/}
-If your state is deeply nested, you might want to consider [flattening it.](/learn/choosing-the-state-structure#avoid-deeply-nested-state) But, if you don't want to change your state structure, you might prefer a shortcut to nested spreads. [Immer](https://github.com/immerjs/use-immer) is a popular library that lets you write using the convenient but mutating syntax and takes care of producing the copies for you. With Immer, the code you write looks like you are "breaking the rules" and mutating an object:
+もし state が深くネストされている場合、[フラットにすることを検討する](/learn/choosing-the-state-structure#avoid-deeply-nested-state)べきかもしれません。しかし、state の構造を変更したくない場合は、スプレッド構文をネストして使うより短いやり方が欲しくなるかもしれません。人気ライブラリである [Immer](https://github.com/immerjs/use-immer) は、使いやすいミューテート型の構文を使って書きつつ、コピーを自動的に作成してくれるというものです。Immer を使うと、あなたのコードは一見オブジェクトをミューテートして「ルール違反」をしているかのように見えます。
```js
updatePerson(draft => {
@@ -660,22 +660,22 @@ updatePerson(draft => {
});
```
-But unlike a regular mutation, it doesn't overwrite the past state!
+しかし、通常のミューテーションとは異なり、過去の state は上書きされません!
-#### How does Immer work? {/*how-does-immer-work*/}
+#### Immer はどのように動作するのか? {/*how-does-immer-work*/}
-The `draft` provided by Immer is a special type of object, called a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), that "records" what you do with it. This is why you can mutate it freely as much as you like! Under the hood, Immer figures out which parts of the `draft` have been changed, and produces a completely new object that contains your edits.
+Immer から渡される `draft` は、[プロキシ (Proxy)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)と呼ばれる特殊なタイプのオブジェクトで、それに対して何を行ったのかを「記録」します。これが好きなだけミューテートができる理由です! 内部では、Immer は `draft` のどの部分が変更されたかを把握し、あなたの編集内容を反映した完全に新しいオブジェクトを生成します。
-To try Immer:
+Immer を試すには:
-1. Run `npm install use-immer` to add Immer as a dependency
-2. Then replace `import { useState } from 'react'` with `import { useImmer } from 'use-immer'`
+1. `npm install use-immer` を実行し、Immer を依存ライブラリとして追加する
+2. 次に `import { useState } from 'react'` を `import { useImmer } from 'use-immer'` に置き換える
-Here is the above example converted to Immer:
+以下は、Immer に変換された上記の例です:
@@ -788,33 +788,33 @@ img { width: 200px; height: 200px; }
-Notice how much more concise the event handlers have become. You can mix and match `useState` and `useImmer` in a single component as much as you like. Immer is a great way to keep the update handlers concise, especially if there's nesting in your state, and copying objects leads to repetitive code.
+イベントハンドラがどれほど簡潔になったか注目してください。`useState` と `useImmer` は 1 つのコンポーネント内で自由に組み合わせることができます。Immer は、state がネストしておりオブジェクトのコピーのためのコードが冗長になりそうな場合でも、更新を行うハンドラを簡潔に保つことができる素晴らしい方法です。
-#### Why is mutating state not recommended in React? {/*why-is-mutating-state-not-recommended-in-react*/}
+#### React ではなぜ state の変更が非推奨なのか? {/*why-is-mutating-state-not-recommended-in-react*/}
-There are a few reasons:
+いくつかの理由があります。
-* **Debugging:** If you use `console.log` and don't mutate state, your past logs won't get clobbered by the more recent state changes. So you can clearly see how state has changed between renders.
-* **Optimizations:** Common React [optimization strategies](/reference/react/memo) rely on skipping work if previous props or state are the same as the next ones. If you never mutate state, it is very fast to check whether there were any changes. If `prevObj === obj`, you can be sure that nothing could have changed inside of it.
-* **New Features:** The new React features we're building rely on state being [treated like a snapshot.](/learn/state-as-a-snapshot) If you're mutating past versions of state, that may prevent you from using the new features.
-* **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.
+* **デバッグ**:`console.log` を使用しているなら、state を書き換えないことにより、古いログの内容が後に起きた state 変更によって上書きされる心配をしなくて済むようになります。つまり、レンダー間で state がどのように変化したかはっきり見ることができるようになります。
+* **最適化**:React の一般的な[最適化戦略](/reference/react/memo)は、前の props や state が次のものと同一である場合作業をスキップする、ということに依存しています。state を書き換えないことで、変更があったかどうかを非常に素早くチェックすることができます。`prevObj === obj` であれば、内部で何も変更されていないと自信を持って言えるようになります。
+* **新機能**:開発中の新しい React の機能は、state が[スナップショットのように扱われること](/learn/state-as-a-snapshot)を前提としています。過去の state の書き換えを行うと、新しい機能を使用できなくなる可能性があります。
+* **仕様変更のしやすさ**:一部のアプリケーション機能(取り消し/やり直し、履歴の表示、フォームを以前の値にリセットするなど)は、ミューテーションが起きないのであれば実装が容易です。これはメモリ内に過去の state のコピーを保持しておけば、必要に応じて再利用できるからです。ミューテーションを行うアプローチで始めてしまうと、このような機能を後で追加するのが困難になることがあります。
+* **実装のシンプルさ**:React はミューテーションの仕組みに依存しないため、オブジェクトに特別なことを一切しなくてすみます。他の多くの「リアクティブ」系ソリューションは、オブジェクトのプロパティを乗っ取ったり、プロキシにラップしたり、初期化時にその他もろもろの作業を行ったりしていますが、React ではその必要がありません。これが、React がどんな大きさのオブジェクトでも、パフォーマンスや正確性の問題を心配せずに state に入れることができる理由でもあります。
-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!
+実際には、React の state をミューテートしても何となく動くこともしばしばあるのですが、上記のようなアプローチを念頭に開発された新しい React 機能を使用できるようにするために、ミューテートを避けることを強くお勧めします。将来のコントリビュータや、将来のあなた自身が、あなたに感謝することでしょう!
-* Treat all state in React as immutable.
-* When you store objects in state, mutating them will not trigger renders and will change the state in previous render "snapshots".
-* Instead of mutating an object, create a *new* version of it, and trigger a re-render by setting state to it.
-* You can use the `{...obj, something: 'newValue'}` object spread syntax to create copies of objects.
-* Spread syntax is shallow: it only copies one level deep.
-* To update a nested object, you need to create copies all the way up from the place you're updating.
-* To reduce repetitive copying code, use Immer.
+* React のすべての state はイミュータブルとして扱う。
+* state にオブジェクトを格納する場合、それらをミューテートしてもレンダーがトリガされない。それは過去のレンダー内の state の「スナップショット」を書き換えているだけである。
+* オブジェクトを書き換える代わりに、新たなバージョンのオブジェクトを作成し、その新しいバージョンに state をセットし、再レンダーをトリガする。
+* `{...obj, something: 'newValue'}` というオブジェクトスプレッド構文を使ってオブジェクトのコピーを作成できる。
+* スプレッド構文は「浅い」、つまり 1 レベルのみのコピーを行う。
+* ネストされたオブジェクトを更新するには、更新している場所から一番上までの全オブジェクトのコピーを作成する必要がある。
+* コピーのためのコードが冗長になったら Immer を使う。
@@ -822,11 +822,11 @@ In practice, you can often "get away" with mutating state in React, but we stron
-#### Fix incorrect state updates {/*fix-incorrect-state-updates*/}
+#### 間違った state 更新を修正 {/*fix-incorrect-state-updates*/}
-This form has a few bugs. Click the button that increases the score a few times. Notice that it does not increase. Then edit the first name, and notice that the score has suddenly "caught up" with your changes. Finally, edit the last name, and notice that the score has disappeared completely.
+このフォームにはいくつかのバグがあります。スコアを増やすボタンを何度かクリックしてみてください。スコアが増えないことに気付くと思います。次に、ファーストネーム欄に入力をしようとすると、思い出したかのようにスコアが最新の値に更新されることを確認してください。最後に、ラストネームを入力してみてください。今度はスコアが完全に消えてしまいます。
-Your task is to fix all of these bugs. As you fix them, explain why each of them happens.
+あなたの仕事はこれらのバグをすべて修正することです。修正しながら、それぞれのバグがなぜ発生するのかを説明してください。
@@ -894,7 +894,7 @@ input { margin-left: 5px; margin-bottom: 5px; }
-Here is a version with both bugs fixed:
+こちらが両方のバグを修正したバージョンです:
@@ -964,23 +964,23 @@ input { margin-left: 5px; margin-bottom: 5px; }
-The problem with `handlePlusClick` was that it mutated the `player` object. As a result, React did not know that there's a reason to re-render, and did not update the score on the screen. This is why, when you edited the first name, the state got updated, triggering a re-render which _also_ updated the score on the screen.
+`handlePlusClick` の問題は、`player` オブジェクトを書き換えてしまっていたことです。その結果、React は再レンダーの必要性を認識せず、画面上のスコアは更新されませんでした。ですがファーストネームを編集すると、対応する state が更新されてレンダーがトリガされるので、その際に画面上の*スコアも併せて*最新の値になった、というわけです。
-The problem with `handleLastNameChange` was that it did not copy the existing `...player` fields into the new object. This is why the score got lost after you edited the last name.
+`handleLastNameChange` の問題は、新しいオブジェクトに既存の `...player` フィールドをコピーしなかったことです。これが、ラストネームを編集した後にスコアが消えてしまった理由です。
-#### Find and fix the mutation {/*find-and-fix-the-mutation*/}
+#### ミューテーションを探して修正 {/*find-and-fix-the-mutation*/}
-There is a draggable box on a static background. You can change the box's color using the select input.
+固定された背景の上にドラッグ可能なボックスが配置されています。ボックスの色は選択ボックスを使って変更できます。
-But there is a bug. If you move the box first, and then change its color, the background (which isn't supposed to move!) will "jump" to the box position. But this should not happen: the `Background`'s `position` prop is set to `initialPosition`, which is `{ x: 0, y: 0 }`. Why is the background moving after the color change?
+しかし、バグがあります。まずボックスを移動し、次にその色を変更しようとすると、(動かないはずの)背景が、ボックスの位置まで「ジャンプ」してしまいます。`Background` の `position` プロパティは `initialPosition` に設定されており、それは `{ x: 0, y: 0 }` となっているのですから、こんなことは起きないはずではないでしょうか。どうして色を変更すると背景が動いてしまうのでしょうか。
-Find the bug and fix it.
+バグを見つけて修正してください。
-If something unexpected changes, there is a mutation. Find the mutation in `App.js` and fix it.
+予期しない変化が起きたということは、ミューテーションがあるということです。`App.js` のミューテーションを見つけて修正してください。
@@ -1130,9 +1130,9 @@ select { margin-bottom: 10px; }
-The problem was in the mutation inside `handleMove`. It mutated `shape.position`, but that's the same object that `initialPosition` points at. This is why both the shape and the background move. (It's a mutation, so the change doesn't reflect on the screen until an unrelated update--the color change--triggers a re-render.)
+問題は `handleMove` 内のミューテーションにあります。`shape.position` を書き換えていますが、それは `initialPosition` が指しているのと同一のオブジェクトです。これが、ボックスと背景が両方動いてしまった原因です。(ミューテーションをしていたためすぐには画面に反映されず、色の変更という無関係な更新により再レンダーがトリガされて初めて、位置の変化が画面に反映されたのです。)
-The fix is to remove the mutation from `handleMove`, and use the spread syntax to copy the shape. Note that `+=` is a mutation, so you need to rewrite it to use a regular `+` operation.
+修正方法は、`handleMove` からミューテーションを除去し、スプレッド構文を使って shape をコピーすることです。`+=` はミューテーションですので、通常の `+` 操作を使って書き直す必要があります。
@@ -1285,9 +1285,9 @@ select { margin-bottom: 10px; }
-#### Update an object with Immer {/*update-an-object-with-immer*/}
+#### Immer を使ってオブジェクトを更新 {/*update-an-object-with-immer*/}
-This is the same buggy example as in the previous challenge. This time, fix the mutation by using Immer. For your convenience, `useImmer` is already imported, so you need to change the `shape` state variable to use it.
+これはひとつ前のチャレンジと同じ、バグのある例です。今回は、Immer を使ってミューテーションを修正してください。`useImmer` はすでにインポートされているので、`shape` という state 変数の部分を変更して `useImmer` を使うようにしてください。
@@ -1454,7 +1454,7 @@ select { margin-bottom: 10px; }
-This is the solution rewritten with Immer. Notice how the event handlers are written in a mutating fashion, but the bug does not occur. This is because under the hood, Immer never mutates the existing objects.
+以下が Immer で書き直した解法です。イベントハンドラがミューテーション形式の書き方になっていますが、バグは発生しないことに注目しましょう。これは、Immer は実際には裏側で、既存のオブジェクトが決して書き換わらないようにしているためです。
diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json
index 3d58bc072..a849a0778 100644
--- a/src/sidebarLearn.json
+++ b/src/sidebarLearn.json
@@ -111,11 +111,11 @@
"path": "/learn/queueing-a-series-of-state-updates"
},
{
- "title": "Updating Objects in State",
+ "title": "state 内のオブジェクトの更新",
"path": "/learn/updating-objects-in-state"
},
{
- "title": "Updating Arrays in State",
+ "title": "state 内の配列の更新",
"path": "/learn/updating-arrays-in-state"
}
]