美文网首页JSReact Native-AndroidRN
React-Native中处理ListView上拉加载更多

React-Native中处理ListView上拉加载更多

作者: 尹_路人 | 来源:发表于2016-07-29 16:58 被阅读13141次

    RN-ListViewLoadMore
    react-native中处理ListView的下拉刷新和上拉加载更多

    ReactNative(RN)中的ListView是一个非常常用的组件,RN中已经有了现成的RefreshControl,官方文档中有具体用法,这里主要记录一下我是如何做上拉加载更多
    示例中的数据来源于阿里巴巴网站

    https://m.alibaba.com/products/tool_boxes/2.html?XPJAX=1
    https://m.alibaba.com/products/tool_boxes/3.html?XPJAX=1
    https://m.alibaba.com/products/tool_boxes/4.html?XPJAX=1
    

    因为没有涉及原生部分代码,且RN组件也是通用的,所以理论上是兼容iOSAndroid

    工程源码在这里(https://github.com/yongqianvip/RN-ListViewLoadMore)

    • 目录结构如图:
      treetree
      熟悉Redux(Redux中文文档) 的对这个结构肯定不陌生,为了尽可能的简单,工程中只保留了单个Action(product.js)和单个Reducer(rootReducer.js)
    • 一定要把控好各种状态

      不管是下拉刷新,还是加载更多,都要有一个对应的状态来控制,以便于加锁,防止重复操作
      如果isLoadingMoretrue,不能再响应LoadMoreData方法
      LoadMoreData结束(成功或失败)后将isLoadingMore置为false

    • 关键方法 onEndReached

      ListView在滚动到最后一个Cell的时候,会触发onEndReached方法,就是从这个方法入手,在ProductList.js中,

        let _pageNo = 2;
        const _pageSize = 30;
        export defaultclass ProductList extends Component {
      
            ...
            
            _toEnd() {
                const { reducer } = this.props;
                //ListView滚动到底部,根据是否正在加载更多 是否正在刷新 是否已加载全部来判断是否执行加载更多
                if (reducer.isLoadingMore || reducer.products.length >= reducer.totalProductCount || reducer.isRefreshing) {
                    return;
                };
                InteractionManager.runAfterInteractions(() => {
                    console.log("触发加载更多 toEnd() --> ");
                    this._loadMoreData();
                });
            }
            _loadMoreData() {
                const { reducer, dispatch } = this.props;
                dispatch(changeProductListLoadingMore(true));
                _pageNo = Number.parseInt(reducer.products.length / _pageSize) + 1;
                dispatch(getProductList(_pageNo));
            }
            _renderFooter() {
                const { reducer } = this.props;
                //通过当前product数量和刷新状态(是否正在下拉刷新)来判断footer的显示
                if (reducer.products.length < 1 || reducer.isRefreshing) {
                    return null
                };
                if (reducer.products.length < reducer.totalProductCount) {
                    //还有更多,默认显示‘正在加载更多...’
                    return <LoadMoreFooter />
                }else{
                    // 加载全部
                    return <LoadMoreFooter isLoadAll={true}/>
                }
            }
      
            render() {
                const { reducer } = this.props;
                const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
                return (
                    <ListView style={ styles.listViewContent } 
                        dataSource={ ds.cloneWithRows(reducer.products) } 
                        renderRow={ this._renderRow.bind(this) }
                        onEndReached={ this._toEnd.bind(this) }
                        onEndReachedThreshold={10}
                        renderFooter={ this._renderFooter.bind(this) }
                        enableEmptySections={true} 
                        refreshControl={
                            <RefreshControl
                                refreshing={ reducer.isRefreshing }
                                onRefresh={ this._onRefresh.bind(this) }
                                tintColor="gray"
                                colors={['#ff0000', '#00ff00', '#0000ff']}
                                progressBackgroundColor="gray"/>
                            }/>
                        
                )
            }
            
            ...
        }
      
    • 加载更多组件LoadMoreFooter

        import React, { Component } from 'react';
        import {
            View,
            Text,
            StyleSheet,
        } from 'react-native';
        class LoadMoreFooter extends Component {
            constructor(props) {
                super(props);
            }
            render() {
                return (
                    <View style={styles.footer}>
                        <Text style={styles.footerTitle}>{this.props.isLoadAll ? '已加载全部' : '正在加载更多……'}</Text>
                    </View>
                )
            }
        }
        const styles = StyleSheet.create({
            footer: {
                flexDirection: 'row',
                justifyContent: 'center',
                alignItems: 'center',
                height: 40,
            },
            footerTitle: {
                marginLeft: 10,
                fontSize: 15,
                color: 'gray'
            }
        })
        
        export default LoadMoreFooter

    相关文章

      网友评论

      • ebf135683f92:大神 我想看下源码 可以么 这个项目在你的git上面已经找不到了 https://github.com/yongqianvip/RN-ListViewLoadMore 。。方便的话 发我下邮箱也好呀 谢谢了 501326265@qq.com 万分感谢
      • 见字如晤一:怎么我按照步骤 1、clone 切分支tag 2、npm install 3、react-native run-android但是一直报错啊
      • Sleet:楼主您好您的代码我明白但是想问问如何处理scrollView中的listView的刷新呢
      • 瘦人假噜噜:您好我想问一下您navigator传递rowData参数时候的语法 为什么加一层{},然后用扩展操作符,扩展操作符的解析有点迷惑,还望指点下 。
        if(navigator) {
        navigator.push({
        component: ProductImageContainer,
        params: {
        rowData
        }
        })
        }

        return <Component {...route.params} navigator={navigator} />
        瘦人假噜噜:@尹_路人 恩项目刚需要用 博主的demo挺不错 我fork拿来学习实验下 多谢分享
        尹_路人:@瘦人假噜噜 多用用 es6就明白了
        瘦人假噜噜:不好意思。。。有点蠢了 es6的语法不太熟悉 原来对象可以直接写入变量...
      • 77323365a2af:你好 ,我看遍js 也没看懂reducer.products是什么意思
        尹_路人:@77323365a2af
        const initialState = {
        products: [],
        isRefreshing: false,
        isLoadingMore: false,
        totalProductCount: 200, //由服务端返回 这里临时指定一个值设置为上限
        tabbarShow: true,
        tabbarHeight: 49,
        viewRecord: [],
        };

        reducer.js 中初始化的时候预设的字段,用来存放请求回来的列表数据
        77323365a2af:@尹_路人 你意思是json数据的字段吗
        尹_路人:@77323365a2af 列表的数据源,可能我的命名不太规范
      • 夏末清茶:我按照你这个方法写的不会停留在当前的位置继续查看数据而是回到第一条,而且footer也显示不出来.问一下博主知道是什么原因吗?
        夏末清茶:@尹_路人 对照的源码写的,没啥思路了,卡在了这儿,想问一下楼主有没有可能知道,可能是什么原因导致的
        尹_路人:@夏末清茶 根据你说的情况我也不确定问题出在哪里,再对照源码看看吧
      • 不帅气的名称:RN有BUG..当listview不足够一屏时会触发onEndReached
        a1d9596b18c9:关于这个问题,我特地来写一下我的解决办法,万一某天有人看到,我也能做了件好事,onEndReached这个属性要跟onEndReachedThreshold这个属性一起用,后面的那个属性里面传的值是一条cell的高度,onEndReachedThreshold={100},例如每条cell的高度是100,这样就能滑倒最后才触发,如果不设置,就会不足一屏触发
        尹_路人:@5670eba33319 @宁毅 是的,ListView的onEndReached方法就是这样的,没有数据源或者数据条数不够铺满一屏就回触发onEndReached方法,可以在onEndReached的函数里结合数据源做一个简单的判断,找到合适的时机 return 出去
        f2b57f7a7e44:@5670eba33319 你怎么解决的啊?我也碰到这个问题了。我现在是一进这个页面就触发onEndReached绑定的函数
      • RN学习:你好大神 我这个接口 上拉刷新 和下拉加载时改变不同的值 我该怎么判断呢
        不帅气的名称:@RN学习 用state控制...刷新时重置变量同加载更多时累计变量

      本文标题:React-Native中处理ListView上拉加载更多

      本文链接:https://www.haomeiwen.com/subject/ylpzjttx.html