列表數據在前端很是常見,咱們常常要處理這種類型的數據,例如文章列表、評論列表、用戶列表…一個前端工程師幾乎天天都須要跟列表數據打交道。html
React.js 固然也容許咱們處理列表數據,但在使用 React.js 處理列表數據的時候,須要掌握一些規則。咱們這一節會專門討論這方面的知識。前端
假設如今咱們有這麼一個用戶列表數據,存放在一個數組當中:數組
const users = [ { username: 'Jerry', age: 21, gender: 'male' }, { username: 'Tomy', age: 22, gender: 'male' }, { username: 'Lily', age: 19, gender: 'female' }, { username: 'Lucy', age: 20, gender: 'female' } ]
若是如今要把這個數組裏面的數據渲染頁面上要怎麼作?開始以前要補充一個知識。以前說過 JSX 的表達式插入 {}
裏面能夠聽任何數據,若是咱們往 {}
裏面放一個存放 JSX 元素的數組會怎麼樣?瀏覽器
... class Index extends Component { render () { return ( <div> {[ <span>React.js </span>, <span>is </span>, <span>good</span> ]} </div> ) } } ReactDOM.render( <Index />, document.getElementById('root') )
咱們往 JSX 裏面塞了一個數組,這個數組裏面放了一些 JSX 元素(其實就是 JavaScript 對象)。到瀏覽器中,你在頁面上會看到:前端工程師
審查一下元素,看看會發現什麼:函數
React.js 把插入表達式數組裏面的每個 JSX 元素一個個羅列下來,渲染到頁面上。因此這裏有個關鍵點:若是你往 {}
放一個數組,React.js 會幫你把數組裏面一個個元素羅列而且渲染出來。優化
知道這一點之後你就能夠知道怎麼用循環把元素渲染到頁面上:循環上面用戶數組裏面的每個用戶,爲每一個用戶數據構建一個 JSX,而後把 JSX 放到一個新的數組裏面,再把新的數組插入 render
方法的 JSX 裏面。看看代碼怎麼寫:this
const users = [ { username: 'Jerry', age: 21, gender: 'male' }, { username: 'Tomy', age: 22, gender: 'male' }, { username: 'Lily', age: 19, gender: 'female' }, { username: 'Lucy', age: 20, gender: 'female' } ] class Index extends Component { render () { const usersElements = [] // 保存每一個用戶渲染之後 JSX 的數組 for (let user of users) { usersElements.push( // 循環每一個用戶,構建 JSX,push 到數組中 <div> <div>姓名:{user.username}</div> <div>年齡:{user.age}</div> <div>性別:{user.gender}</div> <hr /> </div> ) } return ( <div>{usersElements}</div> ) } } ReactDOM.render( <Index />, document.getElementById('root') )
這裏用了一個新的數組 usersElements
,而後循環 users
數組,爲每一個 user
構建一個 JSX 結構,而後 push 到 usersElements
中。而後直接用表達式插入,把這個 userElements
插到 return 的 JSX 當中。由於 React.js 會自動化幫咱們把數組當中的 JSX 羅列渲染出來,因此能夠看到頁面上顯示:spa
但咱們通常不會手動寫循環來構建列表的 JSX 結構,能夠直接用 ES6 自帶的 map
(不瞭解 map
函數的同窗能夠先了解相關的知識再來回顧這裏),代碼能夠簡化成:code
class Index extends Component { render () { return ( <div> {users.map((user) => { return ( <div> <div>姓名:{user.username}</div> <div>年齡:{user.age}</div> <div>性別:{user.gender}</div> <hr /> </div> ) })} </div> ) } }
這樣的模式在 JavaScript 中很是常見,通常來講,在 React.js 處理列表就是用 map
來處理、渲染的。如今進一步把渲染單獨一個用戶的結構抽離出來做爲一個組件,繼續優化代碼:
const users = [ { username: 'Jerry', age: 21, gender: 'male' }, { username: 'Tomy', age: 22, gender: 'male' }, { username: 'Lily', age: 19, gender: 'female' }, { username: 'Lucy', age: 20, gender: 'female' } ] class User extends Component { render () { const { user } = this.props return ( <div> <div>姓名:{user.username}</div> <div>年齡:{user.age}</div> <div>性別:{user.gender}</div> <hr /> </div> ) } } class Index extends Component { render () { return ( <div> {users.map((user) => <User user={user} />)} </div> ) } } ReactDOM.render( <Index />, document.getElementById('root') )
這裏把負責展現用戶數據的 JSX 結構抽離成一個組件 User
,而且經過 props
把 user
數據做爲組件的配置參數傳進去;這樣改寫 Index
就很是清晰了,看一眼就知道負責渲染 users
列表,而用的組件是 User
。
如今代碼運做正常,好像沒什麼問題。打開控制檯看看:
React.js 報錯了。若是須要詳細解釋這裏報錯的緣由,估計要單獨寫半本書。但能夠簡單解釋一下。
React.js 的是很是高效的,它高效依賴於所謂的 Virtual-DOM 策略。簡單來講,能複用的話 React.js 就會盡可能複用,沒有必要的話絕對不碰 DOM。對於列表元素來講也是這樣,可是處理列表元素的複用性會有一個問題:元素可能會在一個列表中改變位置。例如:
<div>a</div> <div>b</div> <div>c</div>
假設頁面上有這麼3個列表元素,如今改變一下位置:
<div>a</div> <div>c</div> <div>b</div>
c
和 b
的位置互換了。但其實 React.js 只須要交換一下 DOM 位置就好了,可是它並不知道其實咱們只是改變了元素的位置,因此它會從新渲染後面兩個元素(再執行 Virtual-DOM 策略),這樣會大大增長 DOM 操做。但若是給每一個元素加上惟一的標識,React.js 就能夠知道這兩個元素只是交換了位置:
<div key='a'>a</div> <div key='b'>b</div> <div key='c'>c</div>
這樣 React.js 就簡單的經過 key
來判斷出來,這兩個列表元素只是交換了位置,能夠儘可能複用元素內部的結構。
這裏沒聽懂沒有關係,後面有機會會繼續講解這部份內容。如今只須要記住一個簡單的規則:對於用表達式套數組羅列到頁面上的元素,都要爲每一個元素加上 key
屬性,這個 key
必須是每一個元素惟一的標識。通常來講,key
的值能夠直接後臺數據返回的 id
,由於後臺的 id
都是惟一的。
在上面的例子當中,每一個 user
沒有 id
能夠用,能夠直接用循環計數器 i
做爲 key
:
... class Index extends Component { render () { return ( <div> {users.map((user, i) => <User key={i} user={user} />)} </div> ) } } ...
再看看,控制檯已經沒有錯誤信息了。但這是很差的作法,這只是掩耳盜鈴(具體緣由你們能夠本身思考一下)。記住一點:在實際項目當中,若是你的數據順序可能發生變化,標準作法是最好是後臺數據返回的 id
做爲列表元素的 key
。