一. 簡介
ListView加載多數(shù)據(jù)時經(jīng)常會用到分頁,Gride排列射亏,滾動等高級操作近忙,下面就簡單介紹下
分頁
當(dāng)數(shù)據(jù)量很大的時候如何分頁加載 。這種情形分兩種情況考慮:
1.數(shù)據(jù)一次性拿到智润,邊滾動邊加載
2.數(shù)據(jù)不是一次性拿到及舍,而是有可能分屏取數(shù)據(jù)
對于第一種情況,在 ListView 內(nèi)部其實已經(jīng)做了分頁的處理:
ListView 內(nèi)部通過 curRenderedRowsCount 狀態(tài)保存已渲染的行數(shù)窟绷;
初始狀態(tài)下锯玛,要加載的數(shù)據(jù)條數(shù)等于 initialListSize (默認為 10 條);
在滾動時檢測當(dāng)前滾動的位置和最底部的距離兼蜈,如果小于 scrollRenderAheadDistance (默認為 1000)更振,就更新 curRenderedRowsCount ,在它原有值基礎(chǔ)上加 pageSize 個(默認為 1 條)饭尝;
由于屬性變化,觸發(fā)了 ListView 重新的 render 献宫。在渲染過程中钥平, curRenderedRowsCount 起到截斷數(shù)據(jù)的作用,React 的 diff 算法使得只有新加入的數(shù)據(jù)才會渲染到了界面上姊途。
整個過程類似于 Web 端懶加載機制涉瘾,即 每次在和底部的距離達到一個閾值時,加載接下來的 pageSize 個數(shù)據(jù) 捷兰。
對于第二種情況立叛,ListView 提供了相關(guān)的屬性:
onEndReachedThreshold ,在滾動即將到達底部時觸發(fā)贡茅;
onEndReached 秘蛇,在已經(jīng)到達底部時觸發(fā)其做;
我們可以在這兩個方法中調(diào)用接口去拿數(shù)據(jù),取到數(shù)據(jù)后再更新數(shù)據(jù)源赁还。
多列(Grid效果)
很多頁面中的列表并非單列的妖泄,乍一看似乎要做出不少調(diào)整,但實際上只通過布局即可達到相關(guān)效果艘策。ListView 并沒有強制要求一個 rowData 在展示時一定要占滿一行蹈胡,在多列的情況下,我們適時調(diào)整每個 rowData 占據(jù)的寬度即可朋蔫。
由于 React Native 使用 Flexbox 進行布局罚渐,給ListView設(shè)置屬性contentContainerStyle;在實現(xiàn)多列時驯妄,主要用到的是 flexWrap:wrap 屬性:它的效果類似于 float荷并,即水平地排列每一項,當(dāng)放不下時進行折行處理富玷。在設(shè)置每行視圖占據(jù)一半寬度后就達到了兩列的效果璧坟,多列的類似。
滾動
ListView 只是整合了數(shù)據(jù)和展現(xiàn)赎懦,但實際滾動的功能還是由 ScrollView 全權(quán)負責(zé)雀鹃。ScrollView 實現(xiàn)完全和平臺相關(guān):在 iOS 上,它映射為 RCTScrollView 励两;在 Android 上黎茎,它映射為 RCTScrollView 和 AndroidHorizontalScrollView 。
React Native 讓不同端上的技術(shù)融合在了一起当悔,同時也給開發(fā)人員提出了更高的要求傅瞻。以 ScrollView 為例,大量的屬性其實原封不動映射給了 UIScrollView 盲憎,這就意味著如果想再深入地研究下去嗅骄,必須對客戶端相關(guān)技術(shù)有足夠了解。無論是前端還是客戶端饼疙,跳出自己熟悉的那片領(lǐng)域也許才是更進一步的關(guān)鍵溺森。
談到滾動,有一點不得不說的就是 列表的無限加載 窑眯,這牽涉到滾動的性能屏积。
Github 上的這個 issue 對此展開了熱烈的討論。其中有人就提到磅甩,數(shù)據(jù)量很大情況下炊林,ListView 在加載時所占用的 CPU 和內(nèi)存會大大增加,滾動到最后就導(dǎo)致了應(yīng)用 crash卷要。
為此渣聚,ListView 中新添加了一個實驗性的屬性: removeClippedSubviews 独榴,它能在滾動時及時刪掉列表中處于視窗的之外的行,以此達到降低內(nèi)存消耗的目的饵逐。不幸的是括眠,即使設(shè)置了這個屬性,程序雖然各項占用減少了不少倍权,但還是沒避免崩潰的命運掷豺。處于好奇,在最新版的 ListView 基礎(chǔ)上做了簡單嘗試薄声,不斷加載一個無限大的列表当船,但并沒有出現(xiàn)崩潰的情況:
即使加載了 3000、4000 行默辨,Android 真機德频、iOS 真機和 iOS 模擬器上都沒有崩潰;
Android 上明顯感到數(shù)據(jù)加載有 階段性的延時 缩幸,即滾動一定程度后壹置,再次滾動數(shù)據(jù)始終加載不出來或要等一段時間才加載出來,體驗較差表谊;iOS 相比要流暢的多钞护;
但不崩潰并非最終的目的,很多 React Native 使用者都在試圖改進 ListView 的性能表現(xiàn)爆办,相比于直接使用 Native 端的組件难咕,ListView 性能還是差強人意,有很大優(yōu)化空間距辆。
ListView 并沒有創(chuàng)造出新的東西余佃,它只是集各家所長,很好地將 React 的視圖渲染和 Native 端很成熟的滾動機制融合在了一起跨算,使用起來和其他組件無差爆土,靜態(tài)地定義View、動態(tài)地組織數(shù)據(jù)诸蚕,是給人帶來的直觀感受步势。
gride示例
class GrideDemo extends Component { constructor(props){ super(props); this.state={ dataSource:new ListView.DataSource({ rowHasChanged:(row1,row2)=> row1!== row2, }), }; } componentWillMount() { this.fetchData(); } render() { if (!this.state.loaded) { //如果movies==null的情況 初始情況 渲染加載視圖 return this.renderLoadingView(); } return ( <ListView dataSource={this.state.dataSource} renderRow={this.renderMovie} //對于listview只加上這句話,并修改布局就行 contentContainerStyle={styles.gride} style={styles.list} /> ); } renderLoadingView() { return ( <View style={styles.container}> <Text> 正在網(wǎng)絡(luò)上獲取電影數(shù)據(jù)…… </Text> </View> ); } //這是渲染一個電影信息 renderMovie(movie) { return ( <View style={styles.container}> <Image source={{uri: movie.posters.thumbnail}} style={styles.thumbnail} /> <Text style={styles.year}>{movie.year}</Text> </View> ); } fetchData() { fetch(REQUEST_URL) .then((response) => response.json()) .then((responseData) => { this.setState({ dataSource: this.state.dataSource.cloneWithRows(responseData.movies), loaded:true, }); }) .done(); //調(diào)用了done() —— 這樣可以拋出異常而不是簡單忽略 } const styles = StyleSheet.create({ list:{ paddingTop: 20, backgroundColor: '#F5FCFF', }, container: { width:100, height:100, margin:10, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, thumbnail: { width: 81, height: 81, borderRadius:10, }, year: { textAlign: 'center', }, gride:{ flexWrap:'wrap', justifyContent:'flex-start', flexDirection:'row' } });
效果
記錄自己的RN學(xué)習(xí)歷程挫望,只用于學(xué)習(xí)交流。