欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

React Native_手把手教你做项目(五.下拉刷新RefreshControl&封装自定义Cell)

程序员文章站 2022-05-30 21:01:46
...

接下来我们继续下拉刷新的功能,主要是缓存数据的拼接与后台服务器的配合。把数据最后的id传给后台,后台根据id返回给你新的id之后的数据,因为没有服务器,所以这里的代码仅仅做演示使用。

下拉刷新RefreshControl

list.js

import React, {Component} from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    ListView,
    TouchableOpacity,
    Image,
    ActivityIndicator,
    RefreshControl
} from 'react-native';

import Icon from 'react-native-vector-icons/Ionicons';
import Dimensions from 'Dimensions';

const {width, height} = Dimensions.get('window');

import config from '../common/config';
import request from '../common/request';

// Mockjs 解析随机的文字
import  Mock from 'mockjs';

let cachedResult = {
    nexPage: 1,
    item: [],
    total: 0,
}

export default class list extends Component {
    constructor(props) {
        super(props);
        this.state = {
            dataSource: new ListView.DataSource({
                rowHasChanged: (r1, r2)=>r1 !== r2,
            }),
            isLoadingTail: false,  //没有加载数据
            isRefreshing: false
        }
    }

    //即将显示
    componentWillMount() {
        //加载本地数据
        // this.dsfetchData();
    }

    componentDidMount() {
        //加载网络数据
        this._fetchData(1);
    }

    _fetchData(page) {

        if (page !== 0) {
            this.setState({
                isLoadingTail: true
            });
        } else {
            this.setState({
                isRefreshing: true
            });
        }

        this.setState({
            isLoadingTail: true
        });

        //发送网络请求
        request.get(config.api.base + config.api.list, {
            accessToken: '001',
            a: 'list',
            c: 'data',
            type: 29,
            page: page
        }).then(
            (data) => {
                //将服务器得到的数据缓存进来
                let items = cachedResult.item.slice();
                // let items = cachedResult.item.concat(data.list);//把缓存的数据进行拼接
                if (page !== 0) {//加载更多
                    items = items.concat(data.list);
                    cachedResult.nexPage += 1;
                } else {//刷新数据
                    items = data.list.concat(items);
                }
                //最后保存数据
                cachedResult.item = items;
                cachedResult.total = items.total;
                // console.log(items);
                // console.log('总数据是:' + cachedResult.total);
                // console.log('当前到了第:' + cachedResult.item.length + '个!');

                if (page !== 0) {//加载更多
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isLoadingTail: false
                    });
                }else {
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isRefreshing: false
                    });
                }

            }
        ).catch(//如果有错
            (error) => {
                if(page !=0){
                    this.setState({
                        isLoadingTail:false
                    })
                }else {
                    this.setState({
                        isRefreshing:false
                    })
                }
                console.log('err' + error);
            }
        )
    }

    // dsfetchData() {
    //     let result = Mock.mock({
    //         "data|20": [
    //             {
    //                 "_id": "@ID",
    //                 "thumb": "@IMG(1024x700,@COLOR(),\'\u56fe\u7247\u4e0a\u7684\u6587\u5b57\')",
    //                 "title": "@cparagraph(1, 3)",
    //                 "video": "\'http:\/\/v.youku.com\/v_show\/id_XMzY5ODY5MDI3Ng==.html?spm=a2h1n.8251846.0.0\'"
    //             }
    //         ],
    //         "success": true
    //     })
    //     this.setState({
    //         dataSource: this.state.dataSource.cloneWithRows(result.data)
    //     })
    // }

    render() {
        return (
            <View style={styles.container}>
                {/*导航条*/}
                <View style={styles.header}>
                    <Text style={styles.headerText}>
                        视频列表
                    </Text>
                </View>
                {/*列表页面*/}
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this._renderRow}
                    style={styles.listView}
                    onEndReached={this._fetchMoreData}//滚到底部加载更多数据
                    onEndReachedThreshold={20} //距离底部还有多远触发
                    renderFooter={this._renderFooter}

                    refreshControl={
                        <RefreshControl
                            refreshing={this.state.isRefreshing}
                            onRefresh={this._onRefresh}
                        />
                    }
                />
            </View>
        );
    }

    _onRefresh = ()=> {
        if (!this._hasMore() || this.state.isRefreshing) {
            return
        }

        this._fetchData(0);
    }
    //自定义Footer视图
    _renderFooter = ()=> {
        if (!this._hasMore() && cachedResult.total !== 0) {
            return (
                <View style={styles.loadingMore}>
                    <Text style={styles.loadingText}>没有更多数据啦...</Text>
                </View>
            )
        }
        // if(!this.state.isLoadingTail){
        //     return(<View></View>)
        // }
        //显示一朵小菊花
        return (
            <ActivityIndicator style={styles.loadingMore}></ActivityIndicator>
        )
    }


    //思路:有多种解决方案

    //1.发送请求 2.保存请求参数 3.对比参数

    //刷新请求 2.保存request = refresh 3.对比 refresh==保存request 状态机中的page值
    //状态机 loading = refresh
    //上拉加载更多数据
    _fetchMoreData = ()=> {
        //判断是否有更多数据或者是否在请求中
        if (!this._hasMore || this.isLoadingTail) {
            return
        }

        let page = cachedResult.nexPage;
        //去服务器去加载更多数据
        this._fetchData(page);
    }

    //判断是否还有更多数据
    _hasMore() {
        return cachedResult.item.length !== cachedResult.total;
    }

    //下划线代表内部类自己用的函数,属于规范
    _renderRow = (rowData)=> {
        return (
            <TouchableOpacity>

                {/*整个Cell*/}
                <View style={styles.cellStyle}>
                    {/*标题文字*/}
                    <Text style={styles.title}>{rowData.text}</Text>


                    <Image style={styles.thumb} source={{uri: rowData.profile_image}}>

                    </Image>
                    <Icon name="ios-play"
                          size={30}
                          style={styles.play}
                    />
                    {/*点赞&评论*/}
                    <View style={styles.cellFooter}>
                        {/*点赞*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-heart-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>点赞</Text>
                        </View>

                        {/*评论*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-chatbubbles-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>评论</Text>
                        </View>
                    </View>
                </View>
            </TouchableOpacity>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    header: {
        // marginTop:Platform.OS == 'ios'?20:0,
        paddingTop: 25,
        paddingBottom: 15,
        backgroundColor: '#dddddd',
        borderBottomWidth: 0.5,
        borderBottomColor: 'black',
    },
    headerText: {
        fontWeight: '600',
        textAlign: 'center',
        fontSize: 16,
    },
    listView: {},
    cellStyle: {
        width: width,
        marginTop: 10,
        backgroundColor: 'white',

    },
    title: {
        padding: 10,
        color: 'black',
        fontSize: 18
    },
    thumb: {
        width: width,
        height: width * 0.56,
        resizeMode: 'cover'
    },
    play: {
        position: 'absolute',
        bottom: 100,
        right: 14,
        width: 46,
        height: 46,
        paddingTop: 8,
        paddingLeft: 18,
        backgroundColor: 'transparent',
        borderColor: 'black',
        borderWidth: 0.5,
        borderRadius: 23,
    },
    cellFooter: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        backgroundColor: '#dddddd',
    },
    footerBox: {
        padding: 10,
        flexDirection: 'row',
        backgroundColor: 'white',
        flex: 1,
        marginLeft: 1,
        justifyContent: 'center',

    },
    boxIcon: {
        fontSize: 22,
        color: '#333',
    },
    boxText: {
        fontSize: 18,
        color: '#333',
        paddingLeft: 12,
        marginTop: 2
    },
    loadingMore: {
        marginVertical: 20
    },
    loadingText: {
        fontSize: 18,
        color: '#777',
        textAlign: 'center'
    }
});

演示示例:

React Native_手把手教你做项目(五.下拉刷新RefreshControl&封装自定义Cell)

封装自定义Cell

从上面的代码中,我们可以看出,仅仅这么low的一个页面,包括css样式,js逻辑代码和render html界面都在list.js文件中,代码300多行,显得十分混乱,那么我们能不能把cell进行抽取呢?

List文件下创建Item.js文件

Item.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, {Component} from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    Image
} from 'react-native';

import Dimensions from 'Dimensions';
const {width, height} = Dimensions.get('window');
import Icon from 'react-native-vector-icons/Ionicons';

export default class item extends Component {

    constructor(props) {
        super(props);
        this.state = {
            rowData: this.props.rowData,
        }
    }

    render() {
        let rowData = this.state.rowData;

        return (
            <TouchableOpacity>

                {/*整个Cell*/}
                <View style={styles.cellStyle}>
                    {/*标题文字*/}
                    <Text style={styles.title}>{rowData.text}</Text>


                    <Image style={styles.thumb} source={{uri: rowData.profile_image}}>

                    </Image>
                    <Icon name="ios-play"
                          size={30}
                          style={styles.play}
                    />
                    {/*点赞&评论*/}
                    <View style={styles.cellFooter}>
                        {/*点赞*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-heart-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>点赞</Text>
                        </View>

                        {/*评论*/}
                        <View style={styles.footerBox}>
                            <Icon name="ios-chatbubbles-outline"
                                  size={30}
                                  style={styles.boxIcon}
                            />
                            {/*点赞文字*/}
                            <Text style={styles.boxText}>评论</Text>
                        </View>
                    </View>
                </View>
            </TouchableOpacity>
        );
    }
}

const styles = StyleSheet.create({
    cellStyle: {
        width: width,
        marginTop: 10,
        backgroundColor: 'white',

    },
    title: {
        padding: 10,
        color: 'black',
        fontSize: 18
    },
    thumb: {
        width: width,
        height: width * 0.56,
        resizeMode: 'cover'
    },
    play: {
        position: 'absolute',
        bottom: 100,
        right: 14,
        width: 46,
        height: 46,
        paddingTop: 8,
        paddingLeft: 18,
        backgroundColor: 'transparent',
        borderColor: 'black',
        borderWidth: 0.5,
        borderRadius: 23,
    },
    cellFooter: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        backgroundColor: '#dddddd',
    },
    footerBox: {
        padding: 10,
        flexDirection: 'row',
        backgroundColor: 'white',
        flex: 1,
        marginLeft: 1,
        justifyContent: 'center',
    },
    boxIcon: {
        fontSize: 22,
        color: '#333',
    },
    boxText: {
        fontSize: 18,
        color: '#333',
        paddingLeft: 12,
        marginTop: 2
    }
});

list.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 * @flow
 */

import React, {Component} from 'react';
import {
    Platform,
    StyleSheet,
    Text,
    View,
    ListView,
    TouchableOpacity,
    Image,
    ActivityIndicator,
    RefreshControl
} from 'react-native';

import Icon from 'react-native-vector-icons/Ionicons';
import Dimensions from 'Dimensions';

const {width, height} = Dimensions.get('window');

import config from '../common/config';
import request from '../common/request';

import Item from './Item';

// Mockjs 解析随机的文字
import  Mock from 'mockjs';

let cachedResult = {
    nexPage: 1,
    item: [],
    total: 0,
}

export default class list extends Component {
    constructor(props) {
        super(props);
        this.state = {
            dataSource: new ListView.DataSource({
                rowHasChanged: (r1, r2)=>r1 !== r2,
            }),
            isLoadingTail: false,  //没有加载数据
            isRefreshing: false
        }
    }

    //即将显示
    componentWillMount() {
        //加载本地数据
        // this.dsfetchData();
    }

    componentDidMount() {
        //加载网络数据
        this._fetchData(1);
    }

    _fetchData(page) {

        if (page !== 0) {
            this.setState({
                isLoadingTail: true
            });
        } else {
            this.setState({
                isRefreshing: true
            });
        }

        this.setState({
            isLoadingTail: true
        });

        //发送网络请求
        request.get(config.api.base + config.api.list, {
            accessToken: '001',
            a: 'list',
            c: 'data',
            type: 29,
            page: page
        }).then(
            (data) => {
                //将服务器得到的数据缓存进来
                let items = cachedResult.item.slice();
                // let items = cachedResult.item.concat(data.list);//把缓存的数据进行拼接
                if (page !== 0) {//加载更多
                    items = items.concat(data.list);
                    cachedResult.nexPage += 1;
                } else {//刷新数据
                    items = data.list.concat(items);
                }
                //最后保存数据
                cachedResult.item = items;
                cachedResult.total = items.total;
                // console.log(items);
                // console.log('总数据是:' + cachedResult.total);
                // console.log('当前到了第:' + cachedResult.item.length + '个!');

                if (page !== 0) {//加载更多
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isLoadingTail: false
                    });
                }else {
                    this.setState({
                        dataSource: this.state.dataSource.cloneWithRows(
                            cachedResult.item
                        ),
                        isRefreshing: false
                    });
                }

            }
        ).catch(//如果有错
            (error) => {
                if(page !=0){
                    this.setState({
                        isLoadingTail:false
                    })
                }else {
                    this.setState({
                        isRefreshing:false
                    })
                }
                console.log('err' + error);
            }
        )
    }

    render() {
        return (
            <View style={styles.container}>
                {/*导航条*/}
                <View style={styles.header}>
                    <Text style={styles.headerText}>
                        视频列表
                    </Text>
                </View>
                {/*列表页面*/}
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this._renderRow}
                    style={styles.listView}
                    onEndReached={this._fetchMoreData}//滚到底部加载更多数据
                    onEndReachedThreshold={20} //距离底部还有多远触发
                    renderFooter={this._renderFooter}

                    refreshControl={
                        <RefreshControl
                            refreshing={this.state.isRefreshing}
                            onRefresh={this._onRefresh}
                        />
                    }
                />
            </View>
        );
    }

    //下拉刷新
    _onRefresh = ()=> {
        if (!this._hasMore() || this.state.isRefreshing) {
            return
        }

        this._fetchData(0);
    }
    //自定义Footer视图
    _renderFooter = ()=> {
        if (!this._hasMore() && cachedResult.total !== 0) {
            return (
                <View style={styles.loadingMore}>
                    <Text style={styles.loadingText}>没有更多数据啦...</Text>
                </View>
            )
        }
        // if(!this.state.isLoadingTail){
        //     return(<View></View>)
        // }
        //显示一朵小菊花
        return (
            <ActivityIndicator style={styles.loadingMore}></ActivityIndicator>
        )
    }


    //思路:有多种解决方案

    //1.发送请求 2.保存请求参数 3.对比参数

    //刷新请求 2.保存request = refresh 3.对比 refresh==保存request 状态机中的page值
    //状态机 loading = refresh
    //上拉加载更多数据
    _fetchMoreData = ()=> {
        //判断是否有更多数据或者是否在请求中
        if (!this._hasMore || this.isLoadingTail) {
            return
        }

        let page = cachedResult.nexPage;
        //去服务器去加载更多数据
        this._fetchData(page);
    }

    //判断是否还有更多数据
    _hasMore() {
        return cachedResult.item.length !== cachedResult.total;
    }

    //返回item
    //下划线代表内部类自己用的函数,属于规范
    _renderRow = (rowData)=> {
        return (
           <Item rowData={rowData} />
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    header: {
        // marginTop:Platform.OS == 'ios'?20:0,
        paddingTop: 25,
        paddingBottom: 15,
        backgroundColor: '#dddddd',
        borderBottomWidth: 0.5,
        borderBottomColor: 'black',
    },
    headerText: {
        fontWeight: '600',
        textAlign: 'center',
        fontSize: 16,
    },
    listView: {

    },
    loadingMore: {
        marginVertical: 20
    },
    loadingText: {
        fontSize: 18,
        color: '#777',
        textAlign: 'center'
    }
});

代码抽取很简单,可以详细看看抽取了哪些代码。

相关标签: reactNative