在 React 中使用 filter() 筛选需要渲染的组件和使用 map() 把数组转换成组件数组。
const people = [
'凯瑟琳·约翰逊: 数学家',
'马里奥·莫利纳: 化学家',
'穆罕默德·阿卜杜勒·萨拉姆: 物理学家',
'珀西·莱温·朱利亚: 化学家',
'苏布拉马尼扬·钱德拉塞卡: 天体物理学家',
];
export default function List() {
const listItems = people.map(person =>
<li>{person}</li>
);
return <ul>{listItems}</ul>;
}
![image]()
首先,把数据 存储 到数组中:
const people = [
'凯瑟琳·约翰逊: 数学家',
'马里奥·莫利纳: 化学家',
'穆罕默德·阿卜杜勒·萨拉姆: 物理学家',
'珀西·莱温·朱利亚: 化学家',
'苏布拉马尼扬·钱德拉塞卡: 天体物理学家',
];
遍历 people 这个数组中的每一项,并获得一个新的 JSX 节点数组 listItems:
const listItems = people.map(person => <li>{person}</li>);
把 listItems 用 <ul> 包裹起来,然后 返回 它:
return <ul>{listItems}</ul>;
因为箭头函数会隐式地返回位于 => 之后的表达式,所以你可以省略 return 语句。
const listItems = chemists.map(person =>
<li>...</li> // 隐式地返回!
);
不过,如果你的 => 后面跟了一对花括号 { ,那你必须使用 return 来指定返回值!
const listItems = chemists.map(person => { // 花括号
return <li>...</li>;
});
箭头函数 => { 后面的部分被称为 “块函数体”,块函数体支持多行代码的写法,但要用 return 语句才能指定返回值。假如你忘了写 return,那这个函数什么都不会返回!
用 key 保持列表项的顺序
如果把上面任何一个沙盒示例在新标签页打开,你就会发现控制台有这样一个报错:
Warning: Each child in a list should have a unique “key” prop.
这是因为你必须给数组中的每一项都指定一个 key——它可以是字符串或数字的形式,只要能唯一标识出各个数组项就行:
<li key={person.id}>...</li>
注意
直接放在 map() 方法里的 JSX 元素一般都需要指定 key 值!
这些 key 会告诉 React,每个组件对应着数组里的哪一项,所以 React 可以把它们匹配起来。这在数组项进行移动(例如排序)、插入或删除等操作时非常重要。一个合适的 key 可以帮助 React 推断发生了什么,从而得以正确地更新 DOM 树。
用作 key 的值应该在数据中提前就准备好,而不是在运行时才随手生成:
utils.js
export function getImageUrl(person) {
return (
'https://i.imgur.com/' +
person.imageId +
's.jpg'
);
}
data.js
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',
},
];
App.js
import { getImageUrl } from "./utils";
import { people } from "./data";
export default function List() {
const chemists = people.filter(person =>
person.profession === "化学家"
);
const listItems = chemists.map(person =>
<li key={person.key}>
<img src={getImageUrl(person)}
alt={person.name}
></img>
{person.name}
{person.profession}
因{person.accomplishment}而闻名世界
</li>
)
return (
<ul>{listItems}</ul>
)
}
![image]()
嵌套列表
data.js:
export const recipes = [
{
id: 'greek-salad',
name: '希腊沙拉',
ingredients: ['西红柿', '黄瓜', '洋葱', '油橄榄', '羊奶酪'],
},
{
id: 'hawaiian-pizza',
name: '夏威夷披萨',
ingredients: ['披萨饼皮', '披萨酱', '马苏里拉奶酪', '火腿', '菠萝'],
},
{
id: 'hummus',
name: '鹰嘴豆泥',
ingredients: ['鹰嘴豆', '橄榄油', '蒜瓣', '柠檬', '芝麻酱'],
},
];
App.js:
import { recipes } from './data.js';
export default function RecipeList() {
return (
<div>
<h1>菜谱</h1>
{recipes.map(recipe=>
<div key={recipe.key}>
<h2>{recipe.name}</h2>
<ul>
{recipe.ingredients.map(ingredient => <li>
{ingredient}
</li>
)}
</ul>
</div>
)
}
</div>
);
}
![image]()
调整App.js 将列表项提取成一个组件:
import { recipes } from './data.js';
function Recipe({ id, name, ingredients }) {
return (
<div>
<h2>{name}</h2>
<ul>
{ingredients.map(ingredient =>
<li key={ingredient}>
{ingredient}
</li>
)}
</ul>
</div>
);
}
export default function RecipeList() {
return (
<div>
<h1>菜谱</h1>
{recipes.map(recipe =>
<Recipe {...recipe} key={recipe.id} />
)}
</div>
);
}
注意这里的 key 是写在 <Recipe> 组件本身上的,不要写在 Recipe 内部返回的 <div> 上。 这是因为 key 只有在就近的数组上下文中才有意义。之前的写法里,我们生成了一个 <div> 的数组所以其中的每一项需要一个 key,但是现在的写法里,生成的实际上是 <Recipe> 的数组。换句话说,在提取组件的时候,key 应该写在复制粘贴的 JSX 的外层组件上。