React文檔(九)list和key


首先,我們回顧一下在js里如何轉換數組。

給出下面的代碼,我們使用map()函數來獲取一個數組的numbers然后將值變成兩倍大。我們分配新數組由map()返回:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);

這段代碼在控制台輸出[2, 4, 6, 8 ,10]。

在React里,把數組轉變成一系列元素也是一樣的。

渲染多個組件

通過使用花括號,你可以創建一組元素,並且把它們包含在JSX里。

下面,我們對numbers數組使用map()函數。為每一項返回一個<li>元素。最后,我們將元素數組處理的結果存為listItems:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li>{number}</li>
);

我們將整個listItems數組放進一個<ul>元素里,然后把它渲染到DOM里:

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

在CodePen里試一試

這段代碼展示了一個1到5的數字列表。

基礎列表組件

通常你會將列表渲染到一個組件里。

我們可以重構上一個例子到一個組件里,這個組件接受一個number數組,輸出一個無序的元素列表。

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需要提供給列表。“key”是一個特殊的字符串屬性當你創建列表元素的時候你所需要的屬性。在下一章節會討論為什么這個屬性很重要。

讓我們在numbers.map()里分配一個key給列表元素來修復沒有key的問題。

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')
);

在CodePen里試一試

keys

key幫助React鑒別哪一項發生了改變,添加了,或者移除了。key應該添加在數組里的元素身上作為一個穩定的特性。(我靠,這個是不是和html里的自定義屬性很像啊)

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

key最好的方式是用一個字符串唯一地標識一個列表的項。多數情況你會使用數據的ID來作為key: 

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);

當你的數據沒有穩定的ID,也許會用數據項的索引作為key:

const todoItems = todos.map((todo, index) =>
  // Only do this if items have no stable IDs
  <li key={index}>
    {todo.text}
  </li>
);

如果數據項可以重排序我們不建議使用索引作為key,因為那樣會降低速度。也許你可以讀一讀這篇深入理解為何key很重要

依據key提取組件

元素的key只有在它和它的兄弟節點對比時才有意義。

舉個例子,如果你提取了一個ListItem組件,你應該保持key在數組里的<listItem />元素里而不是在ListItem的<li>元素里。

例子:錯誤的用法

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')
);

在CodePen里試一試

好的做法就是在map()方法調用里面的元素需要key。

key必須唯一

key跟兄弟節點比較的時候必須唯一。然而不需要全局唯一。當我們創建兩個數組的時候可以出現相同的key。

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')
);

在CodePen里試一試

key對React來說就是一個提示但是它們沒有傳遞給你的組件。如果你需要同樣的值在你的組件里,那就換一個不同的名字把它作為props傳遞:

const content = posts.map((post) =>
  <Post
    key={post.id}
    id={post.id}
    title={post.title} />
);

通過上面的例子,Post組件可以讀取props.id這個屬性,而不是props.key。

在JSX中嵌入map()

 在之前的例子里我們在JSX里聲明了單獨的listItems變量:
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

JSX允許嵌入任何表達式在花括號里因此我們能夠內嵌map()直接到ul里面:

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );
}
有些時候這樣寫可以讓你的代碼更清晰,但是這個風格也能被濫用。就像在js里,決定是否有必要提取一個變量這取決於你。記住如果map()嵌套太深,也許是時候該提取一個組件了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM