自学React-native (第十天)--使用FlatList实现下拉刷新和下拉加载更多

1. 前言:

终于要开始编写业务代码了,今天将组合前面9天学习的内容来制作一个「最热」功能.
在这里插入图片描述

2.代码

View层page/PopularTab.js

import React, { Component } from "react";
import { FlatList, View, Text, StyleSheet, Button, RefreshControl, ActivityIndicator ,DeviceInfo} from "react-native";
import PopularItem from "../common/PopularItem";
import { connect } from "react-redux";
import actions from "../action/index";
import Toast, { DURATION } from 'react-native-easy-toast';
// import NavigationBar from "../common/NavigationBar";
const THEME_COLOR = "red";
const URL = 'https://api.github.com/search/repositories?q=';
const QUERY_STR = '&sort=stars';
const PAGE_SIZE = 10;
class PopularTab extends Component {
    constructor(props) {
        super(props);
        const { tabLabel } = this.props;
        this.storeName = tabLabel;
        this.canLoadMore = false;//防止在初始化时就执行一次loadmore
    }

    genFetchUrl = (storeName) => {
        return `${URL}${storeName}${QUERY_STR}`
    }

    loadData = (more) => {
        const { onLoadPopularData, onLoadMorePopular, popular } = this.props;
        const url = this.genFetchUrl(this.storeName);
        const popularData = popular[this.storeName];
        const that = this;
        if (more) {
            onLoadMorePopular(this.storeName, url, PAGE_SIZE, popularData.pageIndex + 1, popularData.dataArray, function () {
                that.refs.toast.show('没有更多了');
            });
        }
        else {
            onLoadPopularData(this.storeName, url, PAGE_SIZE, function () {
                that.refs.toast.show('已是最新');
            });
        }

    }

    componentDidMount() {
        this.loadData();
    }

    renderItem = (data) => {
        const item = data.item;
        return <PopularItem item={item} />
    }

    //到达底部后触发
    onEndReachedHandler = () => {
        // console.log("没有更多了");
        this.loadData(true);
    }


    EndComponent = (props) => {
        return <View style={styles.footerComponent}>
            <ActivityIndicator style={styles.activity}
                animating={true}
                size={"large"}
                color={THEME_COLOR}
            ></ActivityIndicator>
            <Text>正在加载更多</Text>
        </View>;
    }

    render() {
        const { popular } = this.props;
        let store = popular[this.storeName];//动态获取state
        let { EndComponent, canLoadMore } = this;
        if (!store) {
            store = {
                projectModes: [],
                isLoading: true,
                isLoadingMore: false
            };
        }

        return (
            <View style={styles.container}>
                {
                    store && (!store.projectModes || store.projectModes.length == 0) ?
                        <View style={styles.topActivity}>
                            <ActivityIndicator style={styles.activity}
                                animating={true}
                                size={"large"}
                                // style={{fontSize:30}}
                                color={THEME_COLOR}
                            />
                            <Text style={{ color: THEME_COLOR }}>loading</Text>
                        </View>
                        :
                        <FlatList
                            data={store.projectModes}
                            renderItem={data => this.renderItem(data)}
                            keyExtractor={item => "" + item.id}
                            refreshControl={
                                <RefreshControl
                                    title={"loading"}
                                    titleColor={THEME_COLOR}
                                    colors={[THEME_COLOR]}
                                    refreshing={store.isLoading}
                                    tintColor={THEME_COLOR}
                                    // size={"large"}
                                    onRefresh={() => {
                                        this.loadData();
                                    }}
                                    style={{ fontSize: 30 }}
                                />
                            }

                            ListFooterComponent={store.isLoadingMore ? <EndComponent /> : ""}
                            //到达底部
                            onEndReached={
                                () => {
                                    setTimeout(() => {
                                        if (!this.canLoadMore) return;
                                        this.onEndReachedHandler()
                                        this.canLoadMore = false;
                                        console.log("---------------------到达底部---------------------");
                                    }, 100);
                                }
                            }
                            onEndReachedThreshold={0.5}
                            onMomentumScrollBegin={() => {
                                this.canLoadMore = true;
                                console.log("---------------------开启loadMore---------------------");
                            }}
                        />
                }



                <Toast ref="toast"
                    style={{ backgroundColor: 'black' }}
                    position='top'
                    positionValue={200}
                    fadeInDuration={750}
                    fadeOutDuration={1000}
                    opacity={0.8}
                    textStyle={{ color: 'white' }}

                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    topActivity: {
        marginVertical: 20,
        justifyContent: "center",
        alignItems: "center",
    },
    container: {
        flex: 1,
    },
    footerComponent: {
        flex: 1,
        justifyContent: "center",
        alignItems: "center",
        marginTop: 25
    },
    activity: {
        marginBottom: 5
    }
});

const mapStateToProps = state => ({
    popular: state.popular
});

const mapDispatchToProps = dispatch => ({
    onLoadPopularData: (storeName, url, pageSize, callback) => dispatch(actions.onLoadPopularData(storeName, url, pageSize, callback)),
    onLoadMorePopular: (storeName, url, pageSize, pageIndex, dataArray, callback) => dispatch(actions.onLoadMorePopular(storeName, url, pageSize, pageIndex, dataArray, callback))
});

const PoplarTabPage = connect(mapStateToProps, mapDispatchToProps)(PopularTab);

export default PoplarTabPage;




这里使用了:

  • FlatList 控件.带滚动条的列表组件.
  • RefreshControl控件.下拉组件,用于自定义下方加载组件.
  • ActivityIndicator控件.在RefreshControl中的内嵌组件,用于自定义loading图标动画.
  • react-native-easy-toast.RN的toast通用控件.

遇到的问题:

  • 说实话这里遇到的最大问题其实是redux的流程调试,加载的三个阶段state如何控制,产生干扰如何处理,如何排错等等基本消耗了coder的60%时间,所以养成良好的编码习惯是非常重要的,简单说就是编码习惯和思维方式.不过这里就不展开了.
  • RefreshControl控件的失效问题.当页面被createMaterialTopTabNavigator 封装后,如果页面内部有FlatList,那么第一个tab页面的refreshing属性会失效,也就是尽管refreshing=true,但是loading动画就是不出现,排错到navigation就没法进行下去了,貌似在不通过navigation封装的页面不会有这个问题出现,尝试了半天无果的情况下我使用了ActivityIndicator模拟第一次loading动画的方式解决了这个问题,不过并不完美,头次动画由于和后续动画尺寸上无法一致,会导致比较难看的问题,哪位有解决的方案请私信本人.下面是我的处理方式:
  <View style={styles.container}>
                {
                    store && (!store.projectModes || store.projectModes.length == 0) ?
                        <View style={styles.topActivity}>
                            <ActivityIndicator style={styles.activity}
                                animating={true}
                                size={"large"}
                                // style={{fontSize:30}}
                                color={THEME_COLOR}
                            />
                            <Text style={{ color: THEME_COLOR }}>loading</Text>
                        </View>
                        :
                        <FlatList
                            data={store.projectModes}
                            renderItem={data => this.renderItem(data)}
                            keyExtractor={item => "" + item.id}
                            refreshControl={
                                <RefreshControl
                                    title={"loading"}
                                    titleColor={THEME_COLOR}
                                    colors={[THEME_COLOR]}
                                    refreshing={store.isLoading}
                                    tintColor={THEME_COLOR}
                                    // size={"large"}
                                    onRefresh={() => {
                                        this.loadData();
                                    }}
                                    style={{ fontSize: 30 }}
                                />
                            }

                            ListFooterComponent={store.isLoadingMore ? <EndComponent /> : ""}
                            //到达底部
                            onEndReached={
                                () => {
                                    setTimeout(() => {
                                        if (!this.canLoadMore) return;
                                        this.onEndReachedHandler()
                                        this.canLoadMore = false;
                                        console.log("---------------------到达底部---------------------");
                                    }, 100);
                                }
                            }
                            onEndReachedThreshold={0.5}
                            onMomentumScrollBegin={() => {
                                this.canLoadMore = true;
                                console.log("---------------------开启loadMore---------------------");
                            }}
                        />
                }



                <Toast ref="toast"
                    style={{ backgroundColor: 'black' }}
                    position='top'
                    positionValue={200}
                    fadeInDuration={750}
                    fadeOutDuration={1000}
                    opacity={0.8}
                    textStyle={{ color: 'white' }}

                />
            </View>

3.后记

这篇文章由于记录的是业务代码的编写情况,所以没写太多的知识点,但是说真的看教程和实际写还是很不同的,今天我是决定看了基本思路就完全自己实现这个“最热”功能,真的是收获良多,而这些收获是没法说出来的:比如调试的方式,调试工具的配置,代码的优化等等,建议大家看教程的时候多动手多记录.?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值