首先,讓我們回顧一下你是如何用javascript來轉(zhuǎn)換一個列表。在下面的代碼中,我們用map函數(shù)來使得一個數(shù)字數(shù)組中的數(shù)加倍并且將它打印到控制臺:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
上面這段代碼將在控制臺打印出[2,4,6,8,10],在react中將數(shù)組轉(zhuǎn)化為列表的方法和上面的方法類似。
渲染多個組件
你可以創(chuàng)建一個element的集合并把它們包裹在打括號中,下面的代碼用map函數(shù)將數(shù)組中的數(shù)字全部轉(zhuǎn)換成li元素,最后將它保存到listItems數(shù)組中:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
我們將listItems數(shù)組中的元素插入到ul節(jié)點中,然后將其渲染到dom上:
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
上面的代碼在屏幕上輸出了標為1-5的數(shù)字列表。
基本列表組件
通常情況下,你需要在一個組件中渲染一個列表,我們可以重寫上面的例子,讓創(chuàng)建的組件接收這個數(shù)字數(shù)組,然后返回一個無序列表:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
當你運行上面的代碼時,會報出一串警告:必須為列表的每一個項目提供關鍵字key。當你創(chuàng)建列表是,必須為每一個項目指定特殊的key屬性,我們將在下一章節(jié)討論為什么這一點是非常重要的。
我們來給每一個列表項目指定關鍵字以解決上述問題:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
關鍵字
關鍵字可以幫助react確定哪些列表項被改變,添加或者移除。關鍵字應該被指定給列表中的每一項以便它們有一個確定的ID:
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
你通常會從你的數(shù)據(jù)中獲取ID來為每一項指定關鍵字:
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
如果你沒有一個確定的ID賦給列表項目的話,你可以使用列表的索引值來當作它的關鍵字:
const todoItems = todos.map((todo, index) =>
// Only do this if items have no stable IDs
<li key={index}>
{todo.text}
</li>
);
如果這些列表項會被重新排序的話,我們并不建議你使用索引值來當作其關鍵字,因為這樣會使得渲染變的緩慢。
基于關鍵字抽象組件
關鍵字僅僅在在包裹它的數(shù)組中起作用。比如,如果你抽象出一個名為ListItem的組件,你應該將關鍵字添加在ListItem的聲明上,而不是在LIstItem組件中綁定關鍵字:
- 錯誤的用例
function ListItem(props) {
const value = props.value;
return (
// Wrong! There is no need to specify the key here:
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Wrong! The key should have been specified here:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
- 正確的用例
function ListItem(props) {
// Correct! There is no need to specify the key here:
return <li>{props.value}</li>;
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// Correct! Key should be specified inside the array.
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
** 正確的規(guī)則是在map函數(shù)中綁定關鍵字 **
一個列表中的列表項的關鍵字是唯一的
在一個列表中,所有列表項的關鍵字必須是唯一的,當然,這僅僅在這個列表中如此,全局范圍內(nèi)的列表項的關鍵字不必全都不一樣。我們可以將兩個相同的關鍵字用在不同的數(shù)組中:
function Blog(props) {
const sidebar = (
<ul>
{props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) =>
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar}
<hr />
{content}
</div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
關鍵字為React提供了一個追蹤的屬性,你不需要將它傳遞到組件內(nèi)部,如果在你的組件內(nèi)部需要這個關鍵字的值,你可以將它賦值給不同的命名變量并通過prop傳遞到組件內(nèi)部:
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
在上面的例子中,Post組件可以取得props,id的值,但是取不到props.key的值。
在JSX中插入map函數(shù)
在上面的例子中我們定義一個ListItems的變量并將其插入到JSX中:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
JSX允許我們將表達式插入其中,所以我們可以這樣寫:
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
有時候,上面的表達式是十分簡潔的,但是也有些許困惑,就像在javascript里面一樣。現(xiàn)在,是使用這種簡潔的方式呢,還是像前面的代碼一樣將其抽象成一個變量呢,完全取決于你。還有,若是map函數(shù)中的嵌套的話,將嵌套的東東抽象成一個組件是很棒的實踐方式。