最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React?Native系列之Recyclerlistview使用詳解

 更新時間:2022年10月09日 10:46:45   作者:菜鳥正在搬磚  
這篇文章主要為大家介紹了React?Native系列之Recyclerlistview使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

recyclerlistview的介紹與使用

1.安裝

npm install --save recyclerlistview
或者:
yarn add recyclerlistview

2.概述和功能

RecyclerListView 是一個高性能的列表(listview)組件,同時支持 React NativeWeb ,并且可用于復(fù)雜的列表。RecyclerListView 組件的實現(xiàn)靈感,來自于 Android RecyclerView原生組件及iOS UICollectionView原生組件。

RecyclerListView使用“cell recycling”來重用不再可見的視圖來呈現(xiàn)項目,而不是創(chuàng)建新的視圖對象。 對象的創(chuàng)建非常昂貴并且?guī)в袃?nèi)存開銷,這意味著當(dāng)您滾動列表時內(nèi)存占用量不斷增加。 從內(nèi)存中釋放不可見的項目是另一種技術(shù),但這會導(dǎo)致創(chuàng)建更多的對象和大量的垃圾收集。 回收是渲染無限列表的最佳方式,不會影響性能或內(nèi)存效率。

為什么需要RecyclerListView

我們知道,React Native 的其他列表組件如ListView,會一次性創(chuàng)建所有的列表單元格——cell。如果列表數(shù)據(jù)比較多,則會創(chuàng)建很多的視圖對象,而視圖對象是非常消耗內(nèi)存的。所以,ListView組件,對于我們業(yè)務(wù)中的這種無限列表,基本上是不可以用的。

對于React Native 官方提供的高性能的列表組件FlatList, 在Android設(shè)備上的表現(xiàn),并不是十分友好。它的實現(xiàn)原理,是將列表中不在可視區(qū)域內(nèi)的視圖,進行回收,然后根據(jù)頁面的滾動,不斷的渲染出現(xiàn)在可視區(qū)域內(nèi)的視圖。這里需要注意的是,FlatList是將不可見的視圖回收,從內(nèi)存中清除了,下次需要的時候,再重新創(chuàng)建。這就要求設(shè)備在滾動的時候,能快速的創(chuàng)建出需要的視圖,才能讓列表流暢的展現(xiàn)在用戶面前。而問題也就出現(xiàn)在這里,Android設(shè)備因為老化等原因,計算力等跟不上,加之React Native 本身 JS 層與 Native 層之間交互的一些問題(這里不做深入追究),導(dǎo)致創(chuàng)建視圖的速度達不到使列表流暢滾動的要求。

那怎樣來解決這樣的問題呢?

RecyclerListView 受到 Android RecyclerViewiOS UICollectionView 的啟發(fā),進行兩方面的優(yōu)化:

  • 僅創(chuàng)建可見區(qū)域的視圖,這步與FlatList是一致的。
  • cell recycling,重用單元格,這個做法是FlatList缺乏的。

對于程序來說,視圖對象的創(chuàng)建是非常昂貴的,并且伴隨著內(nèi)存的消耗。意味著如果不斷的創(chuàng)建視圖,在列表滾動的過程中,內(nèi)存占用量會不斷增加。FlatList中將不可見的視圖從內(nèi)存中移除,這是一個比較好的優(yōu)化手段,但同時也會導(dǎo)致大量的視圖重新創(chuàng)建以及垃圾回收。

RecyclerListView 通過對不可見視圖對象進行緩存及重復(fù)利用,一方面不會創(chuàng)建大量的視圖對象,另一方面也不需要頻繁的創(chuàng)建視圖對象和垃圾回收。

基于這樣的理論,所以RecyclerListView的性能是會優(yōu)于FlatList的。

3. RecyclerListView的使用

屬性:

1、dataProvider

首先需要定義一個數(shù)據(jù)驅(qū)動方法

let dataProvider = new DataProvider((r1, r2) => {
    return r1 !== r2;
})

定義完成之后去初始化數(shù)據(jù)

// 列表數(shù)據(jù)
    const [JRecyclerData, setJRecyclerData] = useState(_dataProvider.cloneWithRows(data));

cloneWithRows

  • 想要更新列表的dataProvider數(shù)據(jù)也就是(DataSource)必須每次通過cloneWithRows這個來重新掛載datasource的值。
  • clone方法會自動提取新數(shù)據(jù)并進行逐行對比(使用rowHasChanged方法中的策略),這樣列表就知道哪些行需要重新渲染了。

2、LayoutProvider

定義列表布局

在這之前我們可以根據(jù)我們的業(yè)務(wù)場景,規(guī)劃處幾類的布局,然后自定義每種布局的類型來區(qū)分。

//表示列表中會出現(xiàn)三種ui類型的item
const ViewTypes = {
    FULL: 0,
    HALF_LEFT: 1,
    HALF_RIGHT: 2
}

下面就可以來區(qū)分布局了

  • 為了進行cell-recycling,RecyclerListView要求對每個cell(通常也叫Item)定義一個type,根據(jù)type設(shè)置cell的dim.widthdim.height
//第一個函數(shù)是定義item的ui類型,第二個是定義item的高寬
this._layoutProvider = new LayoutProvider(
    index => {
        if (index % 3 === 0) {
            return ViewTypes.FULL;
        } 
        ...
    },
    (type, dim) => {
        switch (type) {
            case ViewTypes.HALF_LEFT:
                dim.width = width / 2;
                dim.height = 160;
                break;
            ...
        }
    }
)

3、rowRenderer

rowRenderer負(fù)責(zé)渲染一個cell,同樣是根據(jù)type來進行渲染:

_rowRenderer(type, data) {
    switch (type) {
        case ViewTypes.HALF_LEFT:
            return (
                <CellContainer style={styles.containerGridLeft}>
                    <Text>Data: {data}</Text>
                </CellContainer>
            );
        ...
      }
}

例子:

/***
 * To test out just copy this component and render in you root component
 */
export default class RecycleTestComponent extends React.Component {
    constructor(args) {
        super(args);

        let { width } = Dimensions.get("window");

        //Create the data provider and provide method which takes in two rows of data and return if those two are different or not.
        let dataProvider = new DataProvider((r1, r2) => {
            return r1 !== r2;
        });

        //Create the layout provider
        //First method: Given an index return the type of item e.g ListItemType1, ListItemType2 in case you have variety of items in your list/grid
        //Second: Given a type and object set the height and width for that type on given object
        //If you need data based check you can access your data provider here
        //You'll need data in most cases, we don't provide it by default to enable things like data virtualization in the future
        //NOTE: For complex lists LayoutProvider will also be complex it would then make sense to move it to a different file
        this._layoutProvider = new LayoutProvider(
            index => {
                if (index % 3 === 0) {
                    return ViewTypes.FULL;
                } else if (index % 3 === 1) {
                    return ViewTypes.HALF_LEFT;
                } else {
                    return ViewTypes.HALF_RIGHT;
                }
            },
            (type, dim) => {
                switch (type) {
                    case ViewTypes.HALF_LEFT:
                        dim.width = width / 2 - 0.0001;
                        dim.height = 160;
                        break;
                    case ViewTypes.HALF_RIGHT:
                        dim.width = width / 2;
                        dim.height = 160;
                        break;
                    case ViewTypes.FULL:
                        dim.width = width;
                        dim.height = 140;
                        break;
                    default:
                        dim.width = 0;
                        dim.height = 0;
                }
            }
        );

        this._rowRenderer = this._rowRenderer.bind(this);

        //Since component should always render once data has changed, make data provider part of the state
        this.state = {
            dataProvider: dataProvider.cloneWithRows(this._generateArray(300))
        };
    }

    _generateArray(n) {
        let arr = new Array(n);
        for (let i = 0; i < n; i++) {
            arr[i] = i;
        }
        return arr;
    }

    //Given type and data return the view component
    _rowRenderer(type, data) {
        //You can return any view here, CellContainer has no special significance
        switch (type) {
            case ViewTypes.HALF_LEFT:
                return (
                    <CellContainer style={styles.containerGridLeft}>
                        <Text>Data: {data}</Text>
                    </CellContainer>
                );
            case ViewTypes.HALF_RIGHT:
                return (
                    <CellContainer style={styles.containerGridRight}>
                        <Text>Data: {data}</Text>
                    </CellContainer>
                );
            case ViewTypes.FULL:
                return (
                    <CellContainer style={styles.container}>
                        <Text>Data: {data}</Text>
                    </CellContainer>
                );
            default:
                return null;
        }
    }

    render() {
        return <RecyclerListView layoutProvider={this._layoutProvider} dataProvider={this.state.dataProvider} rowRenderer={this._rowRenderer} />;
    }
}
const styles = {
    container: {
        justifyContent: "space-around",
        alignItems: "center",
        flex: 1,
        backgroundColor: "#00a1f1"
    },
    containerGridLeft: {
        justifyContent: "space-around",
        alignItems: "center",
        flex: 1,
        backgroundColor: "#ffbb00"
    },
    containerGridRight: {
        justifyContent: "space-around",
        alignItems: "center",
        flex: 1,
        backgroundColor: "#7cbb00"
    }
};

頁面效果:

但是在實際的業(yè)務(wù)開發(fā)中肯定不會是這么簡單的,一般都會用到分頁,下拉刷新什么的,下面介紹幾個比較常用的屬性:

4、onEndReached

列表觸底是觸發(fā),一般是用來做上拉加載更過數(shù)據(jù)的時候來使用的

<RecyclerListView
    layoutProvider={this._layoutProvider}
    dataProvider={this.dataProvider.cloneWithRows(this.state.infoList)}
    rowRenderer={this._rowRenderer}
    onEndReached={this._onLoadMore}
/>

5、onEndReachedThreshold

列表距離底部多大距離時觸發(fā)onEndReached的回調(diào),這個填寫的是具體的像素值,與FlatList是有區(qū)別的,FlatList填寫的是百分比

<RecyclerListView
    layoutProvider={this._layoutProvider}
    dataProvider={this.dataProvider.cloneWithRows(this.state.infoList)}
    rowRenderer={this._rowRenderer}
    onEndReached={this._onLoadMore}
    onEndReachedThreshold={50}
/>

6、extendedState

在更新目前列表渲染以外的數(shù)據(jù)時,可以使用此屬性更新狀態(tài),以便繪制出新的列表,并且不再重新渲染以前的列表數(shù)據(jù)

<RecyclerListView
    layoutProvider={this._layoutProvider}
    dataProvider={this.dataProvider.cloneWithRows(this.state.infoList)}
    rowRenderer={this._rowRenderer}
    onEndReached={this._onLoadMore}
    onEndReachedThreshold={50}
    extendedState={this.state}
/>

7、scrollViewProps

繼承scrollView的屬性,RecyclerListView本身是不具有刷新屬性的,要想使用刷新功能,就可以繼承scrollView的下拉刷新

<RecyclerListView
    scrollViewProps={{
        refreshControl: (
            <RefreshControl
                refreshing={this.state.loading}
                onRefresh={async () => {
                    this.setState({ loading: true });
                    await this.getInfo();
                    this.setState({ loading: false });
                }}
            />
        )
    }}
/>

下面看一下完整的例子:

import React, { Component } from "react";
import { View, Text, Dimensions, StyleSheet, RefreshControl, Alert } from "react-native";
import { RecyclerListView, DataProvider, LayoutProvider } from "recyclerlistview";
import WBCST from "./../../rn-app";
const ViewTypes = {
    FULL: 0
};
const { width } = Dimensions.get("window");
const styles = StyleSheet.create({
    container: {
        flexDirection: "row",
        justifyContent: "space-between",
        // alignItems: "center",
        flex: 1,
        backgroundColor: "#fff",
        // borderWidth: 1,
        borderColor: "#dddddd",
        margin: 15,
        marginTop: 0,
        padding: 15
    },
    topicLeft: {
        width: width - 210,
        marginRight: 10
    },
    topicRight: {
        backgroundColor: "#f5f5f5",
        width: 140,
        height: 140,
        padding: 15
    },
    topicTitle: {
        color: "#000",
        fontSize: 16,
        fontWeight: "700",
        lineHeight: 28
    },
    topicContext: {
        color: "#999",
        fontSize: 12,
        lineHeight: 18,
        marginTop: 10
    },
    topicNum: {
        fontSize: 14,
        marginTop: 20
    },
    topicRightText: {
        fontSize: 14,
        color: "#666"
    }
});
export default class RecycleTestComponent extends Component {
    constructor(props) {
        super(props);
        this.dataProvider = new DataProvider((r1, r2) => {
            return r1 !== r2;
        });
        let { width } = Dimensions.get("window");
        this._layoutProvider = new LayoutProvider(
            (index) => {
                return ViewTypes.FULL;
            },
            (type, dim) => {
                dim.width = width;
                dim.height = 190;
            }
        );
        this.state = {
            pagenum: 1,
            infoList: [],
            loading: false,
            isLoadMore: false
        };
    }
    getInfo = () => {
        let num = this.state.pagenum;
        let info = this.state.infoList;
        WBCST.getFetch("http://app.58.com/api/community/aggregatepage/tabs/topic", {
            pagesize: 20,
            pagenum: num
        }).then((res) => {
            if (res) {
                let loadMore = false;
                if (num == 1) {
                    if (res.data.questions.length == 20) {
                        loadMore = true;
                    }
                    this.setState({
                        isLoadMore: loadMore,
                        infoList: res.data.questions
                    });
                } else {
                    // info.concat(res.data.questions);
                    if (res.data.questions.length < 20) {
                        loadMore = false;
                    } else {
                        loadMore = true;
                    }
                    this.setState({
                        isLoadMore: loadMore,
                        infoList: this.state.infoList.concat(res.data.questions)
                    });
                }
            }
        });
    };
    _rowRenderer = (type, data) => {
        return (
            <View style={styles.container}>
                <View style={styles.topicLeft}>
                    <Text numberOfLines={2} style={styles.topicTitle}>
                        {data.topic.title}
                    </Text>
                    <Text numberOfLines={2} style={styles.topicContext}>
                        {data.topic.context}
                    </Text>
                    <Text style={styles.topicNum}>
                        {data.topic.pn}
                        人參與此話題
                    </Text>
                </View>
                <View style={styles.topicRight}>
                    <Text style={styles.topicRightText}>{data.user.name}</Text>
                    <Text style={[{ marginTop: 10 }, styles.topicRightText]}>{data.title}</Text>
                </View>
            </View>
        );
    };
    _renderFooter = () => {
        return (
            <View>
                <Text>上拉加載更多</Text>
            </View>
        );
    };
    _onLoadMore = () => {
        // Alert.alert(JSON.stringify("num"));
        if (!this.state.isLoadMore) {
            return;
        }
        let num = this.state.pagenum;
        num = num + 1;
        this.setState(
            {
                pagenum: num
            },
            () => {
                // Alert.alert(JSON.stringify(num));
                this.getInfo();
            }
        );
    };
    componentDidMount = () => {
        this.getInfo();
    };
    render() {
        return (
            <RecyclerListView
                layoutProvider={this._layoutProvider}
                dataProvider={this.dataProvider.cloneWithRows(this.state.infoList)}
                rowRenderer={this._rowRenderer}
                extendedState={this.state}
                onEndReached={this._onLoadMore}
                onEndReachedThreshold={50}
                // renderFooter={this._renderFooter}
                scrollViewProps={{
                    refreshControl: (
                        <RefreshControl
                            refreshing={this.state.loading}
                            onRefresh={async () => {
                                this.setState({ loading: true });
                                // analytics.logEvent("Event_Stagg_pull_to_refresh");
                                await this.getInfo();
                                this.setState({ loading: false });
                            }}
                        />
                    )
                }}
            />
        );
    }
}

效果圖:

RecyclerListView所有屬性

以上就是React Native系列之Recyclerlistview使用詳解的詳細(xì)內(nèi)容,更多關(guān)于React Native使用Recyclerlistview的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React使用context進行跨級組件數(shù)據(jù)傳遞

    React使用context進行跨級組件數(shù)據(jù)傳遞

    這篇文章給大家介紹了React使用context進行跨級組件數(shù)據(jù)傳遞的方法步驟,文中通過代碼示例給大家介紹的非常詳細(xì),對大家學(xué)習(xí)React context組件數(shù)據(jù)傳遞有一定的幫助,感興趣的小伙伴跟著小編一起來學(xué)習(xí)吧
    2024-01-01
  • react vue背景掛載機器問題

    react vue背景掛載機器問題

    這篇文章主要介紹了react vue背景掛載機器問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • ReactNative之FlatList的具體使用方法

    ReactNative之FlatList的具體使用方法

    本篇文章主要介紹了ReactNative之FlatList的具體使用方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • React?中?memo?useMemo?useCallback?到底該怎么用

    React?中?memo?useMemo?useCallback?到底該怎么用

    在React函數(shù)組件中,當(dāng)組件中的props發(fā)生變化時,默認(rèn)情況下整個組件都會重新渲染。換句話說,如果組件中的任何值更新,整個組件將重新渲染,包括沒有更改values/props的函數(shù)/組件。在react中,我們可以通過memo,useMemo以及useCallback來防止子組件的rerender
    2022-10-10
  • 一看就懂的ReactJs基礎(chǔ)入門教程-精華版

    一看就懂的ReactJs基礎(chǔ)入門教程-精華版

    現(xiàn)在最熱門的前端框架有AngularJS、React、Bootstrap等。自從接觸了ReactJS,ReactJs的虛擬DOM(Virtual DOM)和組件化的開發(fā)深深的吸引了我,下面來跟我一起領(lǐng)略ReactJs的風(fēng)采吧~~ 文章有點長,耐心讀完,你會有很大收獲哦
    2021-04-04
  • React實現(xiàn)反向代理和修改打包后的目錄

    React實現(xiàn)反向代理和修改打包后的目錄

    這篇文章主要介紹了React實現(xiàn)反向代理和修改打包后的目錄方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • React服務(wù)端渲染和同構(gòu)的實現(xiàn)

    React服務(wù)端渲染和同構(gòu)的實現(xiàn)

    本文主要介紹了React服務(wù)端渲染和同構(gòu)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • react?redux及redux持久化示例詳解

    react?redux及redux持久化示例詳解

    這篇文章主要為大家介紹了react?redux及redux持久化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Redux模塊化拆分reducer函數(shù)流程介紹

    Redux模塊化拆分reducer函數(shù)流程介紹

    Reducer是個純函數(shù),即只要傳入相同的參數(shù),每次都應(yīng)返回相同的結(jié)果。不要把和處理數(shù)據(jù)無關(guān)的代碼放在Reducer里,讓Reducer保持純凈,只是單純地執(zhí)行計算,這篇文章主要介紹了Redux拆分reducer函數(shù)流程
    2022-09-09
  • React中使用Mobx的方法

    React中使用Mobx的方法

    Mobx是一個前端“狀態(tài)管理框架”,狀態(tài)管理就是將分布在各個組件、各個模塊中的狀態(tài)的變化,按照一定的規(guī)則,進行統(tǒng)一的管理,這篇文章主要介紹了React中如何使用Mobx,需要的朋友可以參考下
    2023-02-02

最新評論

阳新县| 牡丹江市| 葵青区| 汉阴县| 皋兰县| 桓台县| 汾阳市| 思南县| 安徽省| 高碑店市| 沙坪坝区| 绥宁县| 中超| 灌阳县| 大余县| 遵化市| 咸丰县| 托克逊县| 青龙| 丰城市| 洛隆县| 邮箱| 景德镇市| 佛坪县| 吕梁市| 兰溪市| 万州区| 丽江市| 和政县| 济源市| 迭部县| 苗栗县| 榆林市| 黄大仙区| 怀来县| 阳城县| 黑河市| 临泉县| 富阳市| 武宁县| 萍乡市|