本文轉載自:衆成翻譯
譯者: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 在咱們的模板標籤 包括 原生迭代器, 如 map
和 forEach
。github
讓咱們來看看這是什麼意思。讓咱們將上一個示例的 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,參數所在的位置:
- 咱們要克隆的 ReactElement
- 咱們要添加到實例中的任何
props
- 咱們但願它有任何
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應用。
今天的工做很棒!