` 写法:
```js
import { Fragment } from 'react';
@@ -393,46 +414,46 @@ const listItems = people.map(person =>
);
```
-Fragments disappear from the DOM, so this will produce a flat list of ``, `
`, `
`, `
`, and so on.
+这里的 Fragment 标签本身并不会出现在 DOM 上,这串代码最终会转换成 `
`、`
`、`
`、`
`…… 的列表。
-### Where to get your `key` {/*where-to-get-your-key*/}
+### 如何设定 `key` 值 {/*where-to-get-your-key*/}
-Different sources of data provide different sources of keys:
+不同来源的数据往往对应不同的 key 值获取方式:
-* **Data from a database:** If your data is coming from a database, you can use the database keys/IDs, which are unique by nature.
-* **Locally generated data:** If your data is generated and persisted locally (e.g. notes in a note-taking app), use an incrementing counter, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) or a package like [`uuid`](https://www.npmjs.com/package/uuid) when creating items.
+* **来自数据库的数据:** 如果你的数据是从数据库中获取的,那你可以直接使用数据表中的主键,因为它们天然具有唯一性。
+* **本地产生数据:** 如果你数据的产生和保存都在本地(例如笔记软件里的笔记),那么你可以使用一个自增计数器或者一个类似 [`uuid`](https://www.npmjs.com/package/uuid) 的库来生成 key。
-### Rules of keys {/*rules-of-keys*/}
+### key 需要满足的条件 {/*rules-of-keys*/}
-* **Keys must be unique among siblings.** However, it’s okay to use the same keys for JSX nodes in _different_ arrays.
-* **Keys must not change** or that defeats their purpose! Don't generate them while rendering.
+* **key 值在兄弟节点之间必须是唯一的。** 不过不要求全局唯一,在不同的数组中可以使用相同的 key。
+* **key 值不能改变**,否则就失去了使用 key 的意义!所以千万不要在渲染时动态地生成 key。
-### Why does React need keys? {/*why-does-react-need-keys*/}
+### React 中为什么需要 key? {/*why-does-react-need-keys*/}
-Imagine that files on your desktop didn't have names. Instead, you'd refer to them by their order -- the first file, the second file, and so on. You could get used to it, but once you delete a file, it would get confusing. The second file would become the first file, the third file would be the second file, and so on.
+设想一下,假如你桌面上的文件都没有文件名,取而代之的是,你需要通过文件的位置顺序来区分它们———第一个文件,第二个文件,以此类推。也许你也不是不能接受这种方式,可是一旦你删除了其中的一个文件,这种组织方式就会变得混乱无比。原来的第二个文件可能会变成第一个文件,第三个文件会成为第二个文件……
-File names in a folder and JSX keys in an array serve a similar purpose. They let us uniquely identify an item between its siblings. A well-chosen key provides more information than the position within the array. Even if the _position_ changes due to reordering, the `key` lets React identify the item throughout its lifetime.
+React 里需要 key 和文件夹里的文件需要有文件名的道理是类似的。它们(key 和文件名)都让我们可以从众多的兄弟元素中唯一标识出某一项(JSX 节点或文件)。而一个精心选择的 key 值所能提供的信息远远不止于这个元素在数组中的位置。即使元素的位置在渲染的过程中发生了改变,它提供的 `key` 值也能让 React 在整个生命周期中一直认得它。
-You might be tempted to use an item's index in the array as its key. In fact, that's what React will use if you don't specify a `key` at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs.
+你可能会想直接把数组项的索引当作 key 值来用,实际上,如果你没有显式地指定 `key` 值,React 确实默认会这么做。但是数组项的顺序在插入、删除或者重新排序等操作中会发生改变,此时把索引顺序用作 key 值会产生一些微妙且令人困惑的 bug。
-Similarly, do not generate keys on the fly, e.g. with `key={Math.random()}`. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data.
+与之类似,请不要在运行过程中动态地产生 key,像是 `key={Math.random()}` 这种方式。这会导致每次重新渲染后的 key 值都不一样,从而使得所有的组件和 DOM 元素每次都要重新创建。这不仅会造成运行变慢的问题,更有可能导致用户输入的丢失。所以,使用能从给定数据中稳定取得的值才是明智的选择。
-Note that your components won't receive `key` as a prop. It's only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: ``.
+有一点需要注意,组件不会把 `key` 当作 props 的一部分。Key 的存在只对 React 本身起到提示作用。如果你的组件需要一个 ID,那么请把它作为一个单独的 prop 传给组件: ``。
-On this page you learned:
+在这篇文章中,你学习了:
-* How to move data out of components and into data structures like arrays and objects.
-* How to generate sets of similar components with JavaScript's `map()`.
-* How to create arrays of filtered items with JavaScript's `filter()`.
-* Why and how to set `key` on each component in a collection so React can keep track of each of them even if their position or data changes.
+* 如何从组件中抽离出数据,并把它们放入像数组、对象这样的数据结构中。
+* 如何使用 JavaScript 的 `map()` 方法来生成一组相似的组件。
+* 如何使用 JavaScript 的 `filter()` 方法来筛选数组。
+* 为何以及如何给集合中的每个组件设置一个 `key` 值:它使 React 能追踪这些组件,即便后者的位置或数据发生了变化。
@@ -440,11 +461,11 @@ On this page you learned:
-#### Splitting a list in two {/*splitting-a-list-in-two*/}
+#### 把列表一分为二 {/*splitting-a-list-in-two*/}
-This example shows a list of all people.
+下面的示例中有一个包含所有人员信息的列表。
-Change it to show two separate lists one after another: **Chemists** and **Everyone Else.** Like previously, you can determine whether a person is a chemist by checking if `person.profession === 'chemist'`.
+请试着把它分成一前一后的两个列表:分别是 **化学家们** 和 **其余的人**。像之前一样,你可以通过 `person.profession === '化学家'` 这个条件来判断一个人是不是化学家。
@@ -462,13 +483,13 @@ export default function List() {
{person.name}:
{' ' + person.profession + ' '}
- known for {person.accomplishment}
+ 因{person.accomplishment}而闻名世界
);
return (
- Scientists
+ 科学家
);
@@ -476,37 +497,43 @@ export default function List() {
```
```js data.js
-export const people = [{
- id: 0,
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
- accomplishment: 'spaceflight calculations',
- imageId: 'MK3eW3A'
-}, {
- id: 1,
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
- accomplishment: 'discovery of Arctic ozone hole',
- imageId: 'mynHUSa'
-}, {
- id: 2,
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
- accomplishment: 'electromagnetism theory',
- imageId: 'bE7W1ji'
-}, {
- id: 3,
- name: 'Percy Lavon Julian',
- profession: 'chemist',
- accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
- imageId: 'IOjWm71'
-}, {
- id: 4,
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
- accomplishment: 'white dwarf star mass calculations',
- imageId: 'lrWQx8l'
-}];
+export const people = [
+ {
+ id: 0,
+ name: '凯瑟琳·约翰逊',
+ profession: '数学家',
+ accomplishment: '太空飞行相关数值的核算',
+ imageId: 'MK3eW3A',
+ },
+ {
+ id: 1,
+ name: '马里奥·莫利纳',
+ profession: '化学家',
+ accomplishment: '北极臭氧空洞的发现',
+ imageId: 'mynHUSa',
+ },
+ {
+ id: 2,
+ name: '穆罕默德·阿卜杜勒·萨拉姆',
+ profession: '物理学家',
+ accomplishment: '关于基本粒子间弱相互作用和电磁相互作用的统一理论',
+ imageId: 'bE7W1ji',
+ },
+ {
+ id: 3,
+ name: '珀西·莱温·朱利亚',
+ profession: '化学家',
+ accomplishment: '开创性的可的松药物、类固醇和避孕药',
+ imageId: 'IOjWm71',
+ },
+ {
+ id: 4,
+ name: '苏布拉马尼扬·钱德拉塞卡',
+ profession: '天体物理学家',
+ accomplishment: '白矮星质量计算',
+ imageId: 'lrWQx8l',
+ },
+];
```
```js utils.js
@@ -535,7 +562,7 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-You could use `filter()` twice, creating two separate arrays, and then `map` over both of them:
+使用两次 `filter()` 方法来获得两个单独的数组,然后用 `map` 方法分别遍历它们来得到结果。
@@ -545,15 +572,15 @@ import { getImageUrl } from './utils.js';
export default function List() {
const chemists = people.filter(person =>
- person.profession === 'chemist'
+ person.profession === '化学家'
);
const everyoneElse = people.filter(person =>
- person.profession !== 'chemist'
+ person.profession !== '化学家'
);
return (
- Scientists
- Chemists
+ 科学家
+ 化学家
- Everyone Else
+ 其余的人
-In this solution, the `map` calls are placed directly inline into the parent `` elements, but you could introduce variables for them if you find that more readable.
+这个解决方案中,我们直接在父级的 `` 元素里就执行了 `map` 方法。当然如果你想提高代码的可读性,你也可以先用变量保存一下 `map` 之后的结果。
-There is still a bit duplication between the rendered lists. You can go further and extract the repetitive parts into a `` component:
+现在得到的列表中仍然存在一些重复的代码,我们可以更进一步,将这些重复的部分提取成一个 `` 组件:
@@ -672,7 +705,7 @@ function ListSection({ title, people }) {
{person.name}:
{' ' + person.profession + ' '}
- known for {person.accomplishment}
+ 因{person.accomplishment}而闻名世界
)}
@@ -683,21 +716,21 @@ function ListSection({ title, people }) {
export default function List() {
const chemists = people.filter(person =>
- person.profession === 'chemist'
+ person.profession === '化学家'
);
const everyoneElse = people.filter(person =>
- person.profession !== 'chemist'
+ person.profession !== '化学家'
);
return (
- Scientists
+ 科学家
);
@@ -705,37 +738,43 @@ export default function List() {
```
```js data.js
-export const people = [{
- id: 0,
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
- accomplishment: 'spaceflight calculations',
- imageId: 'MK3eW3A'
-}, {
- id: 1,
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
- accomplishment: 'discovery of Arctic ozone hole',
- imageId: 'mynHUSa'
-}, {
- id: 2,
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
- accomplishment: 'electromagnetism theory',
- imageId: 'bE7W1ji'
-}, {
- id: 3,
- name: 'Percy Lavon Julian',
- profession: 'chemist',
- accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
- imageId: 'IOjWm71'
-}, {
- id: 4,
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
- accomplishment: 'white dwarf star mass calculations',
- imageId: 'lrWQx8l'
-}];
+export const people = [
+ {
+ id: 0,
+ name: '凯瑟琳·约翰逊',
+ profession: '数学家',
+ accomplishment: '太空飞行相关数值的核算',
+ imageId: 'MK3eW3A',
+ },
+ {
+ id: 1,
+ name: '马里奥·莫利纳',
+ profession: '化学家',
+ accomplishment: '北极臭氧空洞的发现',
+ imageId: 'mynHUSa',
+ },
+ {
+ id: 2,
+ name: '穆罕默德·阿卜杜勒·萨拉姆',
+ profession: '物理学家',
+ accomplishment: '关于基本粒子间弱相互作用和电磁相互作用的统一理论',
+ imageId: 'bE7W1ji',
+ },
+ {
+ id: 3,
+ name: '珀西·莱温·朱利亚',
+ profession: '化学家',
+ accomplishment: '开创性的可的松药物、类固醇和避孕药',
+ imageId: 'IOjWm71',
+ },
+ {
+ id: 4,
+ name: '苏布拉马尼扬·钱德拉塞卡',
+ profession: '天体物理学家',
+ accomplishment: '白矮星质量计算',
+ imageId: 'lrWQx8l',
+ },
+];
```
```js utils.js
@@ -762,9 +801,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-A very attentive reader might notice that with two `filter` calls, we check each person's profession twice. Checking a property is very fast, so in this example it's fine. If your logic was more expensive than that, you could replace the `filter` calls with a loop that manually constructs the arrays and checks each person once.
+仔细的读者会发现我们在这写了两个 `filter`,对于每个人的职业我们都进行了两次过滤。读取一个属性的值花不了多少时间,因此放在这个简单的示例中没什么大问题。但是如果你的代码逻辑比这里复杂和“昂贵”得多,那你可以把两次的 `filter` 替换成一个只需进行一次检查就能构造两个数组的循环。
-In fact, if `people` never change, you could move this code out of your component. From React's perspective, all that matters is that you give it an array of JSX nodes in the end. It doesn't care how you produce that array:
+实际上,如果 `people` 的数据不会改变,可以直接把这段代码移到组件外面。从 React 的视角来看,它只关心你最后给它的是不是包含 JSX 节点的数组,并不在乎数组是怎么来的:
@@ -775,7 +814,7 @@ import { getImageUrl } from './utils.js';
let chemists = [];
let everyoneElse = [];
people.forEach(person => {
- if (person.profession === 'chemist') {
+ if (person.profession === '化学家') {
chemists.push(person);
} else {
everyoneElse.push(person);
@@ -796,7 +835,7 @@ function ListSection({ title, people }) {
{person.name}:
{' ' + person.profession + ' '}
- known for {person.accomplishment}
+ 因{person.accomplishment}而闻名世界
)}
@@ -808,13 +847,13 @@ function ListSection({ title, people }) {
export default function List() {
return (
- Scientists
+ 科学家
@@ -823,37 +862,43 @@ export default function List() {
```
```js data.js
-export const people = [{
- id: 0,
- name: 'Creola Katherine Johnson',
- profession: 'mathematician',
- accomplishment: 'spaceflight calculations',
- imageId: 'MK3eW3A'
-}, {
- id: 1,
- name: 'Mario José Molina-Pasquel Henríquez',
- profession: 'chemist',
- accomplishment: 'discovery of Arctic ozone hole',
- imageId: 'mynHUSa'
-}, {
- id: 2,
- name: 'Mohammad Abdus Salam',
- profession: 'physicist',
- accomplishment: 'electromagnetism theory',
- imageId: 'bE7W1ji'
-}, {
- id: 3,
- name: 'Percy Lavon Julian',
- profession: 'chemist',
- accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
- imageId: 'IOjWm71'
-}, {
- id: 4,
- name: 'Subrahmanyan Chandrasekhar',
- profession: 'astrophysicist',
- accomplishment: 'white dwarf star mass calculations',
- imageId: 'lrWQx8l'
-}];
+export const people = [
+ {
+ id: 0,
+ name: '凯瑟琳·约翰逊',
+ profession: '数学家',
+ accomplishment: '太空飞行相关数值的核算',
+ imageId: 'MK3eW3A',
+ },
+ {
+ id: 1,
+ name: '马里奥·莫利纳',
+ profession: '化学家',
+ accomplishment: '北极臭氧空洞的发现',
+ imageId: 'mynHUSa',
+ },
+ {
+ id: 2,
+ name: '穆罕默德·阿卜杜勒·萨拉姆',
+ profession: '物理学家',
+ accomplishment: '关于基本粒子间弱相互作用和电磁相互作用的统一理论',
+ imageId: 'bE7W1ji',
+ },
+ {
+ id: 3,
+ name: '珀西·莱温·朱利亚',
+ profession: '化学家',
+ accomplishment: '开创性的可的松药物、类固醇和避孕药',
+ imageId: 'IOjWm71',
+ },
+ {
+ id: 4,
+ name: '苏布拉马尼扬·钱德拉塞卡',
+ profession: '天体物理学家',
+ accomplishment: '白矮星质量计算',
+ imageId: 'lrWQx8l',
+ },
+];
```
```js utils.js
@@ -882,13 +927,13 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-#### Nested lists in one component {/*nested-lists-in-one-component*/}
+#### 嵌套列表 {/*nested-lists-in-one-component*/}
-Make a list of recipes from this array! For each recipe in the array, display its name as an `` and list its ingredients in a ``.
+请根据给你的数组生成菜谱列表!其中每个菜谱,都用 `` 来显示它的名称,并在 `` 里列出它所需的原料。
-This will require nesting two different `map` calls.
+这里的写法需要嵌套两层 `map`。
@@ -900,33 +945,37 @@ import { recipes } from './data.js';
export default function RecipeList() {
return (
-
Recipes
+ 菜谱
);
}
```
```js data.js
-export const recipes = [{
- id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
-}, {
- id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
-}, {
- id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
-}];
+export const recipes = [
+ {
+ id: 'greek-salad',
+ name: '希腊沙拉',
+ ingredients: ['西红柿', '黄瓜', '洋葱', '油橄榄', '羊奶酪'],
+ },
+ {
+ id: 'hawaiian-pizza',
+ name: '夏威夷披萨',
+ ingredients: ['披萨饼皮', '披萨酱', '马苏里拉奶酪', '火腿', '菠萝'],
+ },
+ {
+ id: 'hummus',
+ name: '鹰嘴豆泥',
+ ingredients: ['鹰嘴豆', '橄榄油', '蒜瓣', '柠檬', '芝麻酱'],
+ },
+];
```
-Here is one way you could go about it:
+这是一种可能的解法:
@@ -936,7 +985,7 @@ import { recipes } from './data.js';
export default function RecipeList() {
return (
-
Recipes
+
菜谱
{recipes.map(recipe =>
{recipe.name}
@@ -955,30 +1004,34 @@ export default function RecipeList() {
```
```js data.js
-export const recipes = [{
- id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
-}, {
- id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
-}, {
- id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
-}];
+export const recipes = [
+ {
+ id: 'greek-salad',
+ name: '希腊沙拉',
+ ingredients: ['西红柿', '黄瓜', '洋葱', '油橄榄', '羊奶酪'],
+ },
+ {
+ id: 'hawaiian-pizza',
+ name: '夏威夷披萨',
+ ingredients: ['披萨饼皮', '披萨酱', '马苏里拉奶酪', '火腿', '菠萝'],
+ },
+ {
+ id: 'hummus',
+ name: '鹰嘴豆泥',
+ ingredients: ['鹰嘴豆', '橄榄油', '蒜瓣', '柠檬', '芝麻酱'],
+ },
+];
```
-Each of the `recipes` already includes an `id` field, so that's what the outer loop uses for its `key`. There is no ID you could use to loop over ingredients. However, it's reasonable to assume that the same ingredient won't be listed twice within the same recipe, so its name can serve as a `key`. Alternatively, you could change the data structure to add IDs, or use index as a `key` (with the caveat that you can't safely reorder ingredients).
+`recipes` 数组中每一项都拥有一个 `id`,所以外层的循环可以直接拿它作为 `key`。不过,在循环遍历原料的时候就没有现成的 `id` 可以用了。但是,合理推测一下,一份菜谱里不会罗列多次同一种原料,所以其实原料的名字就适合作为 `key`。此外,你也可以自行修改原本的数据人为增加一项 `id`,或是使用索引作为 `key`(需要注意的是,这么做会使你无法正常地对原料进行排序)。
-#### Extracting a list item component {/*extracting-a-list-item-component*/}
+#### 把列表项提取成一个组件 {/*extracting-a-list-item-component*/}
-This `RecipeList` component contains two nested `map` calls. To simplify it, extract a `Recipe` component from it which will accept `id`, `name`, and `ingredients` props. Where do you place the outer `key` and why?
+`RecipeList` 组件的代码里嵌套了两层 `map`。出于简化代码的考虑,我们提取出一个接受 `id`、`name` 和 `ingredients` 作为 props 的 `Recipe` 组件。这种情况下,你会把外层的 `key` 放在哪里呢?原因是什么?
@@ -988,7 +1041,7 @@ import { recipes } from './data.js';
export default function RecipeList() {
return (
-
Recipes
+
菜谱
{recipes.map(recipe =>
{recipe.name}
@@ -1007,26 +1060,30 @@ export default function RecipeList() {
```
```js data.js
-export const recipes = [{
- id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
-}, {
- id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
-}, {
- id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
-}];
+export const recipes = [
+ {
+ id: 'greek-salad',
+ name: '希腊沙拉',
+ ingredients: ['西红柿', '黄瓜', '洋葱', '油橄榄', '羊奶酪'],
+ },
+ {
+ id: 'hawaiian-pizza',
+ name: '夏威夷披萨',
+ ingredients: ['披萨饼皮', '披萨酱', '马苏里拉奶酪', '火腿', '菠萝'],
+ },
+ {
+ id: 'hummus',
+ name: '鹰嘴豆泥',
+ ingredients: ['鹰嘴豆', '橄榄油', '蒜瓣', '柠檬', '芝麻酱'],
+ },
+];
```
-You can copy-paste the JSX from the outer `map` into a new `Recipe` component and return that JSX. Then you can change `recipe.name` to `name`, `recipe.id` to `id`, and so on, and pass them as props to the `Recipe`:
+你可以将外层 `map` 里的 JSX 复制粘贴到新的 `Recipe` 组件中,并作为这个新组件的返回值。接着把原先的 `recipe.name` 改成 `name`,`recipe.id` 改成 `id`,以此类推,最后把它们作为 props 传给 `Recipe`:
@@ -1051,7 +1108,7 @@ function Recipe({ id, name, ingredients }) {
export default function RecipeList() {
return (
-
Recipes
+
菜谱
{recipes.map(recipe =>
)}
@@ -1061,32 +1118,36 @@ export default function RecipeList() {
```
```js data.js
-export const recipes = [{
- id: 'greek-salad',
- name: 'Greek Salad',
- ingredients: ['tomatoes', 'cucumber', 'onion', 'olives', 'feta']
-}, {
- id: 'hawaiian-pizza',
- name: 'Hawaiian Pizza',
- ingredients: ['pizza crust', 'pizza sauce', 'mozzarella', 'ham', 'pineapple']
-}, {
- id: 'hummus',
- name: 'Hummus',
- ingredients: ['chickpeas', 'olive oil', 'garlic cloves', 'lemon', 'tahini']
-}];
+export const recipes = [
+ {
+ id: 'greek-salad',
+ name: '希腊沙拉',
+ ingredients: ['西红柿', '黄瓜', '洋葱', '油橄榄', '羊奶酪'],
+ },
+ {
+ id: 'hawaiian-pizza',
+ name: '夏威夷披萨',
+ ingredients: ['披萨饼皮', '披萨酱', '马苏里拉奶酪', '火腿', '菠萝'],
+ },
+ {
+ id: 'hummus',
+ name: '鹰嘴豆泥',
+ ingredients: ['鹰嘴豆', '橄榄油', '蒜瓣', '柠檬', '芝麻酱'],
+ },
+];
```
-Here, `
` is a syntax shortcut saying "pass all properties of the `recipe` object as props to the `Recipe` component". You could also write each prop explicitly: `
`.
+这里的 `
` 是一种简写方式,它表示“把 `recipe` 对象里的每个属性都作为 props 传给 `Recipe` 组件”。这和直接写明每一个 prop 是等价的:`
`。
-**Note that the `key` is specified on the `
` itself rather than on the root `` returned from `Recipe`.** This is because this `key` is needed directly within the context of the surrounding array. Previously, you had an array of `
`s so each of them needed a `key`, but now you have an array of `
`s. In other words, when you extract a component, don't forget to leave the `key` outside the JSX you copy and paste.
+**注意这里的 `key` 是写在 `` 组件本身上的,不要写在 `Recipe` 内部返回的 `` 上。** 这是因为 `key` 只有在就近的数组上下文中才有意义。之前的写法里,我们生成了一个 `
` 的数组所以其中的每一项需要一个 `key`,但是现在的写法里,生成的实际上是 `
` 的数组。换句话说,在提取组件的时候,`key` 应该写在复制粘贴的 JSX 的外层组件上。
-#### List with a separator {/*list-with-a-separator*/}
+#### 带有分隔符的列表 {/*list-with-a-separator*/}
-This example renders a famous haiku by Katsushika Hokusai, with each line wrapped in a `` tag. Your job is to insert an `
` separator between each paragraph. Your resulting structure should look like this:
+下面这个示例展示了葛饰北斋一首著名的俳句,它的每一行都由 `` 标签包裹。你需要在段落之间插入分隔符 `
`,最终的结果大概像这样:
```js
@@ -1098,7 +1159,7 @@ This example renders a famous haiku by Katsushika Hokusai, with each line wrappe
```
-A haiku only contains three lines, but your solution should work with any number of lines. Note that `
` elements only appear *between* the `` elements, not in the beginning or the end!
+一首俳句通常只有三行,但是你的解答应当适用于任何行数。注意,`
` 元素只应该在 `` 元素 **之间** 出现,而不是在开头或结尾。
@@ -1141,17 +1202,17 @@ hr {
-(This is a rare case where index as a key is acceptable because a poem's lines will never reorder.)
+(这是一个比较少见的可以把数组索引用作 key 的例子,因为诗句之间的顺序必然是固定的。)
-You'll either need to convert `map` to a manual loop, or use a fragment.
+你可以尝试把原本的 `map` 改造成手动循环,或者试下 fragment 语法。
-You can write a manual loop, inserting `
` and `...
` into the output array as you go:
+可以写一个循环,在循环的过程中把 `
` 和 `...
` 插入到输出的数组:
@@ -1167,7 +1228,7 @@ const poem = {
export default function Poem() {
let output = [];
- // Fill the output array
+ // 填充输出的数组
poem.lines.forEach((line, i) => {
output.push(
@@ -1178,7 +1239,7 @@ export default function Poem() {
);
});
- // Remove the first
+ // 移除第一个
output.shift();
return (
@@ -1206,9 +1267,9 @@ hr {
-Using the original line index as a `key` doesn't work anymore because each separator and paragraph are now in the same array. However, you can give each of them a distinct key using a suffix, e.g. `key={i + '-text'}`.
+原本使用诗句顺序索引作为 `key` 的方法已经行不通了,因为现在数组里同时包含了分隔符和诗句。但是,你可以用添加后缀的形式给它们赋予独一无二的 key 值,比如 `key={i + '-text'}` 这样。
-Alternatively, you could render a collection of fragments which contain `
` and `...
`. However, the `<>...>` shorthand syntax doesn't support passing keys, so you'd have to write `` explicitly:
+另一种做法是,生成包含 `
` 和 `...
` 的 fragment 集合,但因其简写语法 `<> >` 不支持指定 key,所以你需要写成 `` 的形式。
@@ -1254,7 +1315,7 @@ hr {
-Remember, fragments (often written as `<> >`) let you group JSX nodes without adding extra ``s!
+记住,采用 fragment 语法(通常写作 `<> >`)来包裹 JSX 节点可以避免引入额外的 `
` 元素!