diff --git a/beta/src/content/learn/updating-arrays-in-state.md b/beta/src/content/learn/updating-arrays-in-state.md
index eae89facf3..57d6f64f67 100644
--- a/beta/src/content/learn/updating-arrays-in-state.md
+++ b/beta/src/content/learn/updating-arrays-in-state.md
@@ -1,52 +1,56 @@
---
-title: Updating Arrays in State
+title: 更新 state 中的数组
+translators:
+ - yliaz
+ - takeItIzzy
+ - KnowsCount
---
-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.
+数组是另外一种可以存储在 state 中的 JavaScript 对象,它虽然是可变的,但是却应该被视为不可变。同对象一样,当你想要更新存储于 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*/}
+## 在没有 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()`。
-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 的 setting 方法中。为此,你可以通过使用像 `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]` 展开语法([例子](#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 中,更多情况下你会使用 `slice`(没有 `p` !),因为你不想改变 state 中的对象或数组。[更新对象](/learn/updating-objects-in-state)这一章节解释了什么是 mutation,以及为什么不推荐在 state 里这样做。
-### Adding to an array {/*adding-to-an-array*/}
+### 向数组中添加元素 {/*adding-to-an-array*/}
-`push()` will mutate an array, which you don't want:
+`push()` 会直接修改原始数组,而你不希望这样:
@@ -61,7 +65,7 @@ export default function List() {
return (
<>
-
-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:
+相反,你应该创建一个 *新* 数组,其包含了原始数组的所有元素 *以及* 一个在末尾的新元素。这可以通过很多种方法实现,最简单的一种就是使用 `...` [数组展开](a-javascript-refresher#array-spread) 语法:
```js
-setArtists( // Replace the state
- [ // with a new array
- ...artists, // that contains all the old items
- { id: nextId++, name: name } // and one new item at the end
+setArtists( // 替换 state
+ [ // 是通过传入一个新数组实现的
+ ...artists, // 新数组包含原数组的所有元素
+ { id: nextId++, name: name } // 并在末尾添加了一个新的元素
]
);
```
-Now it works correctly:
+现在代码可以正常运行了:
@@ -115,7 +119,7 @@ export default function List() {
return (
<>
-
-The array spread syntax also lets you prepend an item by placing it *before* the original `...artists`:
+数组展开运算符还允许你把新添加的元素放在原始的 `...artists` 之前:
```js
setArtists([
{ id: nextId++, name: name },
- ...artists // Put old items at the end
+ ...artists // 将原数组中的元素放在末尾
]);
```
-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()` 的工作,将新元素添加到数组的末尾和开头。你可以在下面的 sandbox 中尝试一下!
-### 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` 方法实现,例如:
@@ -176,7 +180,7 @@ export default function List() {
return (
<>
-
))}
@@ -200,7 +204,7 @@ export default function List() {
-Click the "Delete" button a few times, and look at its click handler.
+点击“删除”按钮几次,并且查看按钮处理点击事件的代码。
```js
setArtists(
@@ -208,13 +212,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(s => s.id !== artist.id)` 表示“创建一个新的数组,该数组由那些 ID 与 `artists.id` 不同的 `artists` 组成”。换句话说,每个 artist 的“删除”按钮会把 _那一个_ artist 从原始数组中过滤掉,并使用过滤后的数组再次进行渲染。注意,`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()`:
+在下面的例子中,一个数组记录了两个圆形和一个正方形的坐标。当你点击按钮时,仅有两个圆形会向下移动 100 像素。这是通过使用 `map()` 生成一个新数组实现的。
@@ -235,24 +239,24 @@ export default function ShapeEditor() {
function handleClick() {
const nextShapes = shapes.map(shape => {
if (shape.type === 'square') {
- // No change
+ // 不作改变
return shape;
} else {
- // Return a new circle 50px below
+ // 返回一个新的圆形,位置在下方 50px 处
return {
...shape,
y: shape.y + 50,
};
}
});
- // Re-render with the new array
+ // 使用新的数组进行重渲染
setShapes(nextShapes);
}
return (
<>
{shapes.map(shape => (
-### 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` 回调里,第二个参数是元素的索引。使用索引来判断最终是返回原始的元素(即回调的第一个参数)还是替换成其他值:
@@ -303,10 +307,10 @@ export default function CounterList() {
function handleIncrementClick(index) {
const nextCounters = counters.map((c, i) => {
if (i === index) {
- // Increment the clicked counter
+ // 递增被点击的计数器数值
return c + 1;
} else {
- // The rest haven't changed
+ // 其余部分不发生变化
return c;
}
});
@@ -334,11 +338,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`:
+下面的例子中,插入按钮总是会将元素插入到数组中索引为 `1` 的位置。
@@ -359,13 +363,13 @@ export default function List() {
);
function handleClick() {
- const insertAt = 1; // Could be any index
+ const insertAt = 1; // 可能是任何索引
const nextArtists = [
- // Items before the insertion point:
+ // 插入点之前的元素:
...artists.slice(0, insertAt),
- // New item:
+ // 新的元素:
{ id: nextId++, name: name },
- // Items after the insertion point:
+ // 插入点之后的元素:
...artists.slice(insertAt)
];
setArtists(nextArtists);
@@ -374,13 +378,13 @@ export default function List() {
return (
<>
-
-### 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:
+例如:
@@ -430,7 +434,7 @@ export default function List() {
return (
<>
-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.
+然而,**即使你拷贝了数组,你还是不能直接修改其_内部_的元素**。这是因为数组的拷贝是浅拷贝——新的数组中依然保留了与原始数组相同的元素。因此,如果你修改了拷贝数组内部的某个对象,其实你正在直接修改当前的 state。举个例子,像下面的代码就会带来问题。
```js
const nextList = [...list];
-nextList[0].seen = true; // Problem: mutates list[0]
+nextList[0].seen = true; // 问题:直接修改了 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` 是两个不同的数组,**`nextList[0]` 和 `list[0]` 却指向了同一个对象**。因此,通过改变 `nextList[0].seen`,`list[0].seen` 的值也被改变了。这是一种 state 的 mutation 操作,你应该避免这么做!你可以用类似于 [更新嵌套的 JavaScript 对象](docs/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.
+
-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:
+**当你更新一个嵌套的 state 时,你需要从想要更新的地方创建拷贝值,一直这样,直到顶层。** 让我们看一下这该怎么做。
+
+在下面的例子中,两个不同的艺术品清单有着相同的初始 state。他们本应该互不影响,但是因为一次 mutation,他们的 state 被意外地共享了,勾选一个清单中的事项会影响另外一个清单:
@@ -502,12 +508,12 @@ export default function BucketList() {
return (
<>
-
Art Bucket List
-
My list of art to see:
+
艺术愿望清单
+
我想看的艺术清单:
-
Your list of art to see:
+
你想看的艺术清单:
@@ -542,34 +548,34 @@ function ItemList({ artworks, onToggle }) {
-The problem is in code like this:
+问题出在下面这段代码中:
```js
const myNextList = [...myList];
const artwork = myNextList.find(a => a.id === artworkId);
-artwork.seen = nextSeen; // Problem: mutates an existing item
+artwork.seen = nextSeen; // 问题:直接修改了已有的元素
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 `yourArtworks`, 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`,其实是在修改*原始的* artwork 对象。而这个 artwork 对象也被 `yourArtworks` 使用,这样就带来了 bug。这样的 bug 可能难以想到,但好在如果你避免直接修改 state,它们就会消失。
-**You can use `map` to substitute an old item with its updated version without mutation.**
+**你可以使用 `map` 在没有 mutation 的前提下将一个旧的元素替换成更新的版本。**
```js
setMyList(myList.map(artwork => {
if (artwork.id === artworkId) {
- // Create a *new* object with changes
+ // 创建包含变更的*新*对象
return { ...artwork, seen: nextSeen };
} else {
- // No changes
+ // 没有变更
return 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 中的元素会被改变,bug 也就被修复了。
@@ -592,10 +598,10 @@ export default function BucketList() {
function handleToggleMyList(artworkId, nextSeen) {
setMyList(myList.map(artwork => {
if (artwork.id === artworkId) {
- // Create a *new* object with changes
+ // 创建包含变更的*新*对象
return { ...artwork, seen: nextSeen };
} else {
- // No changes
+ // 没有变更
return artwork;
}
}));
@@ -604,10 +610,10 @@ export default function BucketList() {
function handleToggleYourList(artworkId, nextSeen) {
setYourList(yourList.map(artwork => {
if (artwork.id === artworkId) {
- // Create a *new* object with changes
+ // 创建包含变更的*新*对象
return { ...artwork, seen: nextSeen };
} else {
- // No changes
+ // 没有变更
return artwork;
}
}));
@@ -615,12 +621,12 @@ export default function BucketList() {
return (
<>
-
Art Bucket List
-
My list of art to see:
+
艺术愿望清单
+
我想看的艺术清单:
-
Your list of art to see:
+
你想看的艺术清单:
@@ -655,16 +661,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.
+通常来讲,**你应该只直接修改你刚刚创建的对象**。如果你正在插入一个*新*的 artwork,你可以修改它,但是如果你想要改变的是 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):
+在没有 mutation 的前提下更新嵌套数组可能会变得有点重复。[就像对对象一样](/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 。如果你有此类需求,你或许需要[调整一下数据的结构](/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 来重写的艺术愿望清单的例子:
@@ -707,12 +713,12 @@ export default function BucketList() {
return (
<>
-
Art Bucket List
-
My list of art to see:
+
艺术愿望清单
+
我想看的艺术清单:
-
Your list of art to see:
+
你想看的艺术清单:
@@ -765,7 +771,7 @@ function ItemList({ artworks, onToggle }) {
-Note how with Immer, **mutation like `artwork.seen = nextSeen` is now okay:**
+请注意当使用 Immer 时,**类似 `artwork.seen = nextSeen` 这种会产生 mutation 的语法不会再有任何问题了:**
```js
updateMyTodos(draft => {
@@ -774,17 +780,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`.
+这是因为你并不是在直接修改_原始的_ state,而是在修改 Immer 提供的一个特殊的 `draft` 对象。同理,你也可以为 `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 中,但你不应该直接修改它。
+- 不要直接修改数组,而是创建它的一份 *新的* 拷贝,然后使用新的数组来更新它的状态。
+- 你可以使用 `[...arr, newItem]` 这样的数组展开语法来向数组中添加元素。
+- 你可以使用 `filter()` 和 `map()` 来创建一个经过过滤或者变换的数组。
+- 你可以使用 Immer 来保持代码简洁。
@@ -792,9 +798,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` 的逻辑,以便按下“+”时递增对应数字:
@@ -852,7 +858,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` 函数创建一个新数组,然后使用 `...` 对象展开语法为新数组创建一个变更后对象的拷贝值:
@@ -919,9 +925,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。
@@ -991,7 +997,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` 的商品:
@@ -1080,9 +1086,9 @@ button { margin: 5px; }
-#### Fix the mutations using non-mutative methods {/*fix-the-mutations-using-non-mutative-methods*/}
+### 使用不会直接修改原始值的方法修复 mutation 的问题 {/*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` 中所有的事件处理程序都会产生 mutation。这导致编辑和删除待办事项的功能无法正常运行。使用不会直接修改原始值的方法重写 `handleAddTodo`、`handleChangeTodo` 和 `handleDeleteTodo` 这三个函数:
@@ -1156,7 +1162,7 @@ export default function AddTodo({ onAddTodo }) {
+ }}>添加
>
)
}
@@ -1200,7 +1206,7 @@ function Task({ todo, onChange, onDelete }) {
});
}} />
>
);
@@ -1209,7 +1215,7 @@ function Task({ todo, onChange, onDelete }) {
<>
{todo.title}
>
);
@@ -1228,7 +1234,7 @@ function Task({ todo, onChange, onDelete }) {
/>
{todoContent}
);
@@ -1245,7 +1251,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` 创建一个新数组。现在列表可以正常工作了:
@@ -1323,7 +1329,7 @@ export default function AddTodo({ onAddTodo }) {
+ }}>添加
>
)
}
@@ -1367,7 +1373,7 @@ function Task({ todo, onChange, onDelete }) {
});
}} />
>
);
@@ -1376,7 +1382,7 @@ function Task({ todo, onChange, onDelete }) {
<>
{todo.title}
>
);
@@ -1395,7 +1401,7 @@ function Task({ todo, onChange, onDelete }) {
/>
{todoContent}
);
@@ -1413,9 +1419,9 @@ ul, li { margin: 0; padding: 0; }
-#### Fix the mutations using Immer {/*fix-the-mutations-using-immer*/}
+### 使用 Immer 修复 mutation 的问题 {/*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 来修复 mutation 的问题。为了方便,`useImmer` 已经被引入了,你需要使用它来替换 `todos` 的 state 变量。
@@ -1490,7 +1496,7 @@ export default function AddTodo({ onAddTodo }) {
+ }}>添加
>
)
}
@@ -1534,7 +1540,7 @@ function Task({ todo, onChange, onDelete }) {
});
}} />
>
);
@@ -1543,7 +1549,7 @@ function Task({ todo, onChange, onDelete }) {
<>
{todo.title}
>
);
@@ -1562,7 +1568,7 @@ function Task({ todo, onChange, onDelete }) {
/>
{todoContent}
);
@@ -1597,7 +1603,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` 的一部分,你就可以以 mutation 的方式写代码。这里所有的 mutation 都在 `draft` 上执行,因此代码可以正常运行:
@@ -1678,7 +1684,7 @@ export default function AddTodo({ onAddTodo }) {
+ }}>添加
>
)
}
@@ -1722,7 +1728,7 @@ function Task({ todo, onChange, onDelete }) {
});
}} />
>
);
@@ -1731,7 +1737,7 @@ function Task({ todo, onChange, onDelete }) {
<>
{todo.title}
>
);
@@ -1750,7 +1756,7 @@ function Task({ todo, onChange, onDelete }) {
/>
{todoContent}
);
@@ -1783,9 +1789,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` 方法:
@@ -1863,7 +1869,7 @@ export default function AddTodo({ onAddTodo }) {
+ }}>添加
>
)
}
@@ -1907,7 +1913,7 @@ function Task({ todo, onChange, onDelete }) {
});
}} />
>
);
@@ -1916,7 +1922,7 @@ function Task({ todo, onChange, onDelete }) {
<>
{todo.title}
>
);
@@ -1935,7 +1941,7 @@ function Task({ todo, onChange, onDelete }) {
/>
{todoContent}
);
@@ -1968,7 +1974,7 @@ ul, li { margin: 0; padding: 0; }
-With Immer, you can pick the style that feels the most natural for each separate case.
+通过使用 Immer ,你可以为每个单独的场景选择最为自然的代码风格。