react native Expo完全基于ScrollView实现的下拉刷新和上拉触底加载

我直接封装成了一个组件

props参数为

static propTypes = {
        style:PropTypes.object, // 样式
        refreshing:PropTypes.bool.isRequired,//是否开始下拉刷新动画
        refreshBegin: PropTypes.func,// 开始下拉刷新回调
        scrollEnd: PropTypes.func,// 触底回调
    };

使用示例

import React from 'react';
import {
    View,
} from 'react-native';
import styles from './style';
import HomeSwiper from "../../../components/HomeSwiper";
import HomeVideo from "../../../components/HomeVideo";
import ScrollViewPull from "../../../components/ScrollViewPull";
import {connect} from 'react-redux'; // 引入connect函数
import {
    getHomeSwiper,
    getHomeVideoCard,
    handleRefreshStatus
} from '../../../actions/homeRecommendAction';

class HomeRecommend extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            refreshing: false,
        };
    }

    componentDidMount(){
        const {homeVideoCard} = this.props;
        this.props.getVideoCard(undefined,1,homeVideoCard);
        this.props.getSwiper();
    }

    // 触底
    handleScrollEnd = () => {
        const {currentPage,lastPage,homeVideoCard} = this.props;
        if(currentPage === lastPage){
            this.props.getVideoCard(undefined,currentPage+1,homeVideoCard);
        }
    };

    // 开始下拉刷新
    handleRefreshBegin = () => {
        const {homeVideoCard} = this.props;
        this.props.getChangeRefresh(true);
        this.props.getSwiper();
        this.props.getVideoCard(undefined,1,homeVideoCard);
    };

    render() {
        const {navigation,swiperData,leftVideoData,rightVideoData,refreshing} = this.props;
        return (
            <ScrollViewPull
                style={styles.scroll}
                refreshing={refreshing}
                scrollEnd={()=>this.handleScrollEnd()} // 触底回调
                refreshBegin={()=>this.handleRefreshBegin()} // 开始下拉刷新回调
            >
                <View style={styles.container}>
                    <HomeSwiper
                        navigation={navigation}
                        swiperData={swiperData}
                    />
                    <View style={styles.border}/>
                    <HomeVideo
                        navigation={navigation}
                        leftVideoData={leftVideoData}
                        rightVideoData={rightVideoData}
                    />
                </View>
            </ScrollViewPull>
        );
    }
}

const mapStateToProps = (state) => ({
    swiperData : state.homeRecommend.homeSwiperData,
    currentPage : state.homeRecommend.currentPage,
    homeVideoCard: state.homeRecommend.homeVideoCard,
    leftVideoData : state.homeRecommend.leftVideoData,
    rightVideoData : state.homeRecommend.rightVideoData,
    refreshing: state.homeRecommend.refreshing
});

const mapDispatchToProps = (dispatch) => ({
    getSwiper(){
        dispatch(getHomeSwiper());
    },
    getChangeRefresh(refresh){
        dispatch(handleRefreshStatus(refresh));
    },
    getVideoCard(id,page,homeVideoCard){
        dispatch(getHomeVideoCard(id,page,homeVideoCard));
    },
});

export default connect(mapStateToProps,mapDispatchToProps)(HomeRecommend);

组件全部代码为:

import React from 'react';
import {
    ScrollView,
    RefreshControl,
} from 'react-native';
import PropTypes from 'prop-types';

class ScrollViewPull extends React.Component {
    static navigationOptions = {
        header: null,
    };

    static propTypes = {
        style:PropTypes.object, // 样式
        refreshing:PropTypes.bool.isRequired,//是否开始下拉刷新动画
        refreshBegin: PropTypes.func,// 开始下拉刷新回调
        scrollEnd: PropTypes.func,// 触底回调
    };

    constructor(props) {
        super(props);
        this.initState();
    }


    initState=()=>{

    };

    onRefresh = () => {
        this.props.refreshBegin();
    };

    // 监听上拉触底
    _contentViewScroll = (e: Object) => {
        let offsetY = e.nativeEvent.contentOffset.y; //滑动距离
        let contentSizeHeight = e.nativeEvent.contentSize.height; //scrollView contentSize高度
        let oriageScrollHeight = e.nativeEvent.layoutMeasurement.height; //scrollView高度
        if (offsetY + oriageScrollHeight >= contentSizeHeight){
            this.props.scrollEnd();
        }
    };

    render() {
        const {children,refreshing,style} = this.props;
        return (
            <ScrollView
                style={[{flex:1},style]}
                showsVerticalScrollIndicator={false}
                scrollToIndex
                refreshControl={
                    <RefreshControl
                        refreshing={refreshing}
                        onRefresh={this.onRefresh}
                    />
                }
                onMomentumScrollEnd = {this._contentViewScroll}
            >
                {children}
            </ScrollView>
        );
    }
}

export default ScrollViewPull;