美文网首页ReactNative笔记程序员@IT·互联网
RN笔记-ListView上拉加载更多功能

RN笔记-ListView上拉加载更多功能

作者: 金丝楠 | 来源:发表于2017-03-26 02:02 被阅读1055次

    React-Native中使用ListView时一般都会用到下拉刷新和上拉加载更多功能,系统提供有RefreshControl下拉刷新组件,简单易用。
    在做上拉加载更多功能时却比较麻烦,在仔细研究了ReactNative官网文档之后,依然没有找到实现办法,但是可以了解到上拉加载功能肯定离不开ListView的两个属性onEndReachedonEndReachedThreshold

    官网文档中同时提到了renderFooter页脚渲染属性,网上搜到的很多也用到了这个属性,但是我在使用过程中发现它对我并没有帮助

    onEndReached

    当所有的数据都已经渲染过,并且列表被滚动到距离最底部不足onEndReachedThreshold个像素的距离时调用。原生的滚动事件会被作为参数传递。译注:当第一次渲染时,如果数据不足一屏(比如初始值是空的),这个事件也会被触发,请自行做标记过滤。

    onEndReachedThreshold

    调用onEndReached之前的临界值,单位是像素。

    下面记录我在实现上拉加载功能的具体方法和代码。首先自定义正在加载更多和已加载全部的组件,新建LoadMoreFooter.js文件,复制粘贴以下代码。

    import React, { Component } from 'react';
      import {
          View,
          Text,
          StyleSheet,
          ActivityIndicator
      } from 'react-native';
    
      var LoadMoreFooter = React.createClass ({
          getDefaultProps(){
            return{
              isLoadAll:false
            }
          },
          render() {
              return (
                  <View style={styles.footer}>
                      <ActivityIndicator animating={!this.props.isLoadAll} />
                      <Text style={styles.footerTitle}>{this.props.isLoadAll ? '已加载全部' : '正在加载更多…'}</Text>
                  </View>
              )
          }
      })
    
      var styles = StyleSheet.create({
          footer: {
              flexDirection: 'row',
              justifyContent: 'center',
              alignItems: 'center',
              height: 30,
          },
          footerTitle: {
              marginLeft: 10,
              fontSize: 13,
              color: 'gray'
          }
      })
    
    module.exports = LoadMoreFooter;
    

    接下来要处理自定义加载更多组件的显示与隐藏逻辑。当this.state.isLoadMore ==true时显示<LoadMoreFooter />组件,否则为null

      render() {
        return (
            this.state.isEmptyData ?
            this.isEmptyData() :
            <View style={styles.container}>
              { /*列表*/ }
              <ListView
                dataSource={this.state.dataSource}
                renderRow={this.renderRow}
                onEndReached={this._toEnd}
                onEndReachedThreshold={10}
                // renderFooter={this._toEnd}
                refreshControl={
                 <RefreshControl
                 refreshing={this.state.isRefreshing}
                 tintColor="gray"
                 title="正在刷新"
                 onRefresh={this._onRefresh}/>}
              />
              {
                this.state.isLoadMore ?
                <LoadMoreFooter isLoadAll={!this.state.isLoadMore} />
                : null
              }
          </View>
        );
      },
    

    下面要处理的是加载数据时最复杂的逻辑关系:刷新当前数据、还是加载更多数据。这里定义了this.state.isRefreshing属性来区分是否正在刷新当前数据。同时定义了this.state.data属性,当正在加载更多数据时,需要在当前页列表dataSource的基础上追加下一页的数据,即[...this.state.data , ...JSON.parse(responseData).data]

    向动态数组中添加对象,使用的是方法是[...array_one , ...array_two],与OC中的可变数组不同。

      getInitialState(){
        //创建数据源
        var ds = new ListView.DataSource({rowHasChanged:(row1, row2) => row1 !== row2});
        //初始化数据源
        return {
          data:null,
          dataSource: ds,
          isEmptyData:false,
          isRefreshing:true,
          extend:'',
          isLoadMore:false,
          page:1
        }
      },
    
      //当列表滑动到最后一个Cell时,调用此方法
      _toEnd(){
        if (this.state.isRefreshing==false && this.state.data.length>=_pageSize) {
          this.setState({
            isLoadMore:true,
          })
          // 立即更改属性值 page+1
          this.state.page = this.state.page + 1
          // 网络请求数据
          this.getEduData();
        }
      },
    
    

    注意事项:
    react native setState之后的state值不能立即使用,setState之后,需要走完RN生命周期,也就是走到render时,state的值才会变成setState的值,要立即使用state的值,需要直接更改,也即this.state.something = 'now';
    所以在设置page页码加1时,不能直接在setState中设置,要实现page属性立刻加1,使用this.state.page = this.state.page + 1

    数据请求成功后,要在请求成功的回调方法中更新数据源。使用三木运算来分别更新刷新页面数据、和加载更多数据时的业务逻辑。

        // 更新数据源
        var data = this.state.data;
        if (!JSON.parse(responseData).data || JSON.parse(responseData).data.length==0) {
          this.setState({
            isEmptyData: this.state.isLoadMore ? false : true,
            isRefreshing:false,
            isLoadMore:false
          });
          if (this.state.isLoadMore) {
            // 立即更改属性值 page-1
            this.state.page = this.state.page - 1
          }
        } else {
          data = this.state.isLoadMore ? [...this.state.data , ...JSON.parse(responseData).data] : JSON.parse(responseData).data
          this.setState({
            data:data,
            isRefreshing:false,
            dataSource:this.state.dataSource.cloneWithRows(data),
            isLoadMore:false,
          });
        }
    

    如果请求的数据为空,展示给用户提示信息。

      isEmptyData(){
        return (
          <ScrollView style={{backgroundColor:'#e8e8e8'}}>
            <View style={styles.emptyDataStyle}>
              <Image source={{uri:'bv_dropbox'}} style={styles.emptyDataIcon}/>
              <Text style={{marginTop:5,color:'gray'}}>暂未有资讯</Text>
            </View>
          </ScrollView>
        )
      }
    

    相关文章

      网友评论

        本文标题:RN笔记-ListView上拉加载更多功能

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