【全棧React】第13天: 重複元素

本文轉載自:衆成翻譯
譯者:iOSDevLog
連接:http://www.zcfy.cc/article/3826
原文:https://www.fullstackreact.com/30-days-of-react/day-13/javascript

今天,咱們將經過如何顯示多個組件來準備將外部數據引入咱們的應用。html

咱們已經構建了一個沒有任何外部數據的基本應用。在咱們實現以前 (咱們將在明天開始這個功能), 讓咱們來看看過去兩週中咱們所掩蓋的事情:java

重複元素

咱們已經看到了這以前, 咱們已經遍歷了一個對象列表, 並在屏幕上呈現多個組件。在咱們的應用中添加太多的複雜度來加載外部數據以前, 今天咱們將快速瞭解如何在應用中重複組件/元素。react

因爲 jsx 被瀏覽器視爲純 javascript 的, 咱們可使用任何 傳統 javascript 內的模板標籤中的 jsx。咱們已經看到了這一行動。做爲一個快速演示:git

const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li>{i}</li>
      })}
    </ul>
  )
}

注意模板標籤{} 內的內容看起來簡單的 javascript。那是由於它 只是 javascript。此功能容許咱們使用 (大多數) 的 javascript 在咱們的模板標籤 包括 原生迭代器, 如 mapforEachgithub

讓咱們來看看這是什麼意思。讓咱們將上一個示例的 a 值從單個整數轉換爲整數列表:web

const a = [1, 10, 100, 1000, 10000];

咱們能夠將 a 變量映射到咱們的組件中, 並返回將爲咱們構建虛擬 DOM 的響應組件列表。npm

const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li>{i}</li>
      })}
    </ul>
  )
}

什麼是map() 函數?api

map() 函數是數組中一個原生javascript內置函數的。
它接受在數組的每一個元素上運行的函數, 所以, 上面的函數將運行四次, 其值爲i 開始爲1 , 而後它將再次運行它的第二個值, i將被設置爲10 等等等等。數組

讓咱們更新咱們在第12天建立的應用與咱們的 App 組件在這裏。讓咱們打開咱們的src/App.js 文件, 並將 App 組件的內容替換爲此源。清理一些未使用的變量和您的src/App.js應該相似於如下內容:

import React from 'react';

const a = [1, 10, 100, 1000, 10000];
const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li>{i}</li>
      })}
    </ul>
  )
}

export default App

使用create-react-app命令生成的命令再次啓動應用:npm start, 咱們能夠看到應用在瀏覽器中工做!

可是, 若是咱們打開開發人員控制檯, 咱們將看到打印出錯誤。此錯誤是由如下事實引發的: React不知道如何跟蹤咱們列表中的各個組件, 由於它們只是看起來像一個 <li />組件。

出於性能緣由, React使用虛擬 DOM 嘗試限制在從新視圖時須要更新的 DOM 元素的數量。若是沒有任何變化, React不會使瀏覽器更新任何東西以節省工做。

此功能很是適合於構建 web 應用, 但有時咱們必須經過爲節點提供惟一標識符來幫助作出React。在映射列表和渲染組件是其中之一。

React要求咱們經過使用特殊屬性來識別唯一的組件, 這是列表中每一個元素的 key 屬性。key 屬性能夠是任何咱們想要的, 但它 必須是惟一的 的元素。在咱們的示例中, 咱們能夠在 map 中使用i變量, 由於數組中沒有其餘元素具備相同的值。

讓咱們更新映射來設置key:

const App = (props) => {
  return (
    <ul>
      {a.map(i => {
        return <li key={i}>{i}</li>
      })}
    </ul>
  )
}

子組件

咱們在本週早些時候談到了創建父子關係的事情, 可是讓咱們更詳細地介紹一下如何訪問父組件中的子組件, 以及如何呈現它們。

在第11天, 咱們構建了一個 <Formatter />組件來處理時鐘組件中的日期格式, 以使用戶可以靈活地使用本身的自定義時鐘渲染。回想一下, 咱們所建立的實現其實是至關醜陋和相對複雜的。

const Formatter = (props) => {
  let children = props.format.split('').map((e, idx) => {
    if (e === 'h') {
      return <Hour key={idx} {...props} />
    } else if (e === 'm') {
      return <Minute key={idx} {...props} />
    } else if (e === 's') {
      return <Second key={idx} {...props} />
    } else if (e === 'p') {
      return <Ampm key={idx} {...props} />
    } else if (e === ' ') {
      return <span key={idx}> </span>;
    } else {
      return <Separator key={idx} {...props} />
    }
  });

  return <span>{children}</span>;
}

咱們能夠用React.Children 對象來映射一個React對象的列表, 並讓React作這個自舉。其結果是一個更乾淨的 Formatter組件 (不是完美的, 但可以使用的):

const Formatter = ({format, state}) => {
  let children = format.split('').map(e => {
    if (e == 'h') {
      return <Hour />
    } else if (e == 'm') {
      return <Minute />
    } else if (e == 's') {
      return <Second />
    } else if (e == 'p') {
      return <Ampm />
    } else if (e == ' ') {
      return <span> </span>;
    } else {
      return <Separator />
    }
  });
  return (<span>
      {React.Children
        .map(children, c => React.cloneElement(c, state))}
      </span>)
}

React.cloneElement

咱們尚未談論React.cloneElement() 函數, 因此讓咱們簡單地看看它。
記得 WWWWWAAAAAYYYYY(way) 回到第2天, 咱們看了如何瀏覽器 看待 JSX? 它把它變成了相似於以下的 javascript:

React.createElement("div", null, 
  React.createElement("img", {src: "profile.jpg", alt: "Profile photo"}),
  React.createElement("h1", null, "Welcome back Ari")
);

React.cloneElement() 爲咱們處理這個。有時咱們會想複製它或添加自定義props/children的組件,而不是建立一個新的組件實例 (若是咱們已經有一個)。因此咱們能夠保留它建立的相同的屬性。咱們能夠用React.cloneElement() 來爲咱們處理這一切。

React.cloneElement()React.createElement() 函數有相同的api,參數所在的位置:

  1. 咱們要克隆的 ReactElement
  2. 咱們要添加到實例中的任何 props
  3. 咱們但願它有任何children

在咱們的 Formatter 示例中, 咱們正在建立列表中全部子級 (<Hour />, <Minute />等組件) 並將state 對象做爲其屬性。

React.Children 的對象提供了一些很好的實用工具來處理children的函數。上面的 Formatter 示例使用 map 函數循環訪問子級, 並在列表中克隆每個。它爲每個建立一個key (若是須要), 使咱們沒必要本身管理惟一性。

讓咱們使用React.Children.map() 函數更新咱們的應用組件:

const App = (props) => {
  return (
    <ul>
      {React.Children.map(a, i => <li>{i}</li>)}
    </ul>
  )
}

在瀏覽器中, 一切仍然正常。

React.Children 中還有其餘一些很是有用的方法,咱們將主要使用React.Children.map() 函數,但瞭解其餘可用的 對咱們來講也是很好的。 點擊文檔 查看更多列表。

經過這一點, 咱們只處理了本地數據, 而不是真正關注遠程數據 (儘管咱們在構建活動提要組件時 已經 簡要地提到了它)。明天, 咱們將進入與服務器的互動, 因此咱們可使用它在咱們的React應用。

今天的工做很棒!

相關文章
相關標籤/搜索