最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 体验小程序 react hook——实现列表加载

    正文概述 掘金(可汗)   2021-03-05   630

    函数页面配置

    function TestPage() {
    }
    TestPage.config = {
    //在这里配置小程序页面相关内容
    }
    export default TestPage
    

    函数组件配置

    function TestCom(props) {
    }
    TestCom.options = {
        addGlobalClass: true
    }
    export default TestCom
    

    数据加载

    const [list, setList] = useState([])
    useEffect( async () => {
        let data = await getData()
        setList(data)
    }, [])//传空数组模拟componentDidMount 功能
    

    写一个列表加载组件

    功能分析

    • 空状态
    • 下拉刷新
    • 上拉加载
    • 加载完成提示
    • 加载截流

    实现方案

    • 使用小程序的下拉刷新和上拉加载功能
    • 抽象空状态组件
    • 自定义effect抽象加载方案

    列表组件代码 1.0

    import {View} from "@tarojs/components";
    import Empty from "../empty";
    
    function List(props) {
        const { listTotal, listLength, emptyTip, children } = props
        let isEmpty = listLength === 0
        let isLast = listLength >= listTotal
        return (
            <View>
                {
                    children//列表内容
                }
                {
                    isEmpty//列表为空时显示
                    &&
                    <Empty title={emptyTip} />
                }
                
                {
                    !isEmpty && isLast//非空状态加载完毕显示
                    &&
                    <View className='paddingY30 color-5 font-size-4 text-align-center'>我也是有底线的</View>
                }
            </View>
        )
    }
    
    List.options = {
        addGlobalClass: true
    }
    
    export default List
    

    useGetList 1.0 实现下拉加载

    
    import Taro, {useEffect, useReachBottom, useState} from "@tarojs/taro";
    
    export default function useGetList(getList) {//接收数据加载方法为参数
        if (!getList) return []
        const [list, setList] = useState([]);//列表数据
        const [page, setPage] = useState(1);//列表页
        useEffect(async ()=>{
            try {
                let {list: listGet} = await getList(page)
                let newList =  page === 1 ? listGet : [...list, ...listGet]
                setList(newList)//更新列表
            } catch (e) {
                console.log(e)
            }
        }, [page])//页数改变的时候执行
    
        useReachBottom(()=> {
            let pageMore = page + 1
            setPage(pageMore)
        })
        return list
    }
    

    useGetList 1.1 实现加载中截流和加载完毕截流

    默认后端返回列表总数,没有就让后端

    
    import Taro, {useEffect, useReachBottom, useState} from "@tarojs/taro";
    
    export default function useGetList(getList) {
        if (!getList) return []
        const [list, setList] = useState([]);
        const [page, setPage] = useState(1);
        const [count, setCount] = useState(null); //列表总数
        let loading = false //判断是否正在加载
        useEffect(async ()=>{
            let isLast = typeof count === 'number' && list.length >= count //判断是否已经加载完毕
            let isStop = loading || isLast //是否截流:正在加载或者下拉加载已经完毕
            if (!isStop) {
                loading = true
                try {
                    let {list: listGet, count: countGet} = await getList(page) //默认后端返回列表总数
                    let newList =  page === 1 ? listGet : [...list, ...listGet]
                    setList(newList)
                    countGet !== count && setCount(countGet) //更新列表总数
                } catch (e) {
                    console.log(e)
                }
                setTimeout(()=> {
                    loading = false //重置加载状态
                }, 0)
            }
        }, [page])//页数改变的时候执行
    
        useReachBottom(()=> {
            let pageMore = page + 1
            setPage(pageMore)
        })
        return list
    }
    

    useGetList 2.0 实现下拉刷新

    考虑到page=1时刷新需求

    同时下拉刷新与上来加载属于不同加载类型

    所以增加参数——加载类型type,作为执行useEffect回调条件

    import Taro, {useEffect, usePullDownRefresh, useReachBottom, useState} from "@tarojs/taro";
    
    export default function useGetList(getList) {
        if (!getList) return []
        const [page, setPage] = useState(1);
        const [list, setList] = useState([]);
        const [count, setCount] = useState(null);
        const [type, setType] = useState('load');//加载类型,'load','refresh'等
        let loading = false
        useEffect(async ()=>{
            let isLast = typeof count === 'number' && list.length >= count
            let isLoadMore = type === 'load'//判断是否为下拉加载
            let isStop = loading || (isLoadMore && isLast)//正在加载或者下拉加载已经完毕——截流
            if (!isStop) {
                loading = true
                try {
                    let {list: listGet, count: countGet} = await getList(page)
                    let newList =  page === 1 ? listGet : [...list, ...listGet]
                    setList(newList)
                    countGet !== count && setCount(countGet)
                } catch (e) {
                    console.log(e)
                }
                setTimeout(()=> {
                    type === 'refresh' && Taro.stopPullDownRefresh() //下拉刷新停止
                    loading = false
                }, 0)
            }
    
        }, [page, type]) //页数改变或者加载类型改变的时候执行
    
        useReachBottom(()=> {
            let pageMore = page + 1
            setPage(pageMore)
            type !== 'load' && setType('load') //重置加载状态
        })
    
        usePullDownRefresh(()=>{ //注意页面需要配置允许刷新
            setType('refresh') //更改加载状态
            page !== 1 && setPage(1)
        })
        return [list, count]
    }
    
    Index.config = {
        navigationBarTitleText: '测试页面',
        enablePullDownRefresh: true //页面配置下拉刷新
    }
    

    到这里小程序的列表加载组件已经可以用了


    使用例子

    import { View } from "@tarojs/components";
    import DeviceCard from "../../components/device/deviceCard";
    import List from "../../components/list";
    import useGetList from "../../effects/useGetList";
    
    //这个函数可以提取到后端请求文件里
    async function getDevices(page) {
        let list =  [
            {
                image: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3744924158,1824985192&fm=26&gp=0.jpg',
                title: '1如何轻松在Coinicgame',
                content: '维马逊自动封口机商用全自动连续热封机来自雅马哈',
                id: 1
            },
            {
                image: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3744924158,1824985192&fm=26&gp=0.jpg',
                title: '2如何轻松在Coinicgame',
                content: '维马逊自动封口机商用全自动连续热封机来自雅马哈',
                id: 2
            }
        ]
        return {list, count: 24}
    }
    
    function Index() {
        const [list , count] = useGetList(getDevices, null)
        return (
            <View className='padding-bottom20'>
                <List length={list ? list.length : null}
                      count={count}>
                    <View className='marginX20 flex-wrap'>
                        {
                            list && list.length && list.map((device,index) => (
                                <DeviceCard key={device.name + index}
                                            device={device} />
                            ))
                        }
                    </View>
                </List>
            </View>
        )
    }
    
    Index.config = {
        navigationBarTitleText: '测试设备列表',
        enablePullDownRefresh: true
    }
    
    export default Index
    
    

    优化目标

    • 列表组件支持接收列表子组件作为参数
    • 扩展列表数据筛选功能——搜索、筛选

    useGetList 3.0 增加搜索/筛序功能

    import Taro, {useEffect, usePullDownRefresh, useReachBottom, useState} from "@tarojs/taro";
    //暴露筛序更新方法
    function createUseFilter(setPage, setType, setFilter) {
        return (filter) => {
            setPage(1)
            setType('search')
            setFilter(filter)
        }
    }
    export default function useGetList(getList) {
        if (!getList) return []
        const [list, setList] = useState([]);
        const [count, setCount] = useState(null);
        const [page, setPage] = useState(1);
        const [type, setType] = useState('load');
        const [filter, setFilter] = useState({}); //增加筛序条件
        let loading = false
        useEffect(async ()=>{
            let isLast = typeof count === 'number' && list.length >= count
            let isLoadMore = type === 'load'
            let isStop = loading || (isLoadMore && isLast)
            if (!isStop) {
                loading = true
                try {
                    let {list: listGet, count: countGet} = await getList(page, filter) //传入筛选条件
                    let newList =  page === 1 ? listGet : [...list, ...listGet]
                    setList(newList)
                    countGet !== count && setCount(countGet)
                } catch (e) {
                    console.log(e)
                }
                type === 'refresh' && Taro.stopPullDownRefresh()
                setTimeout(()=> {
                    loading = false
                }, 0)
            }
    
        }, [page, type, filter])
        useReachBottom(()=> {
            let pageMore = page + 1
            setPage(pageMore)
            setType('load')
        })
        usePullDownRefresh(()=>{
            setPage(1)
            setType('refresh')
        })
        return [list, count, filter, createUseFilter(setPage, setType, setFilter)] //暴露筛选更新方法和目前筛选条件
    }
    

    使用

    let searchInv = -1
    
    function Index() {
        const [list , count, filter, useActionFilter] = useGetList(getDevices, {search: ''})
        return (
            <View className='news-manage padding-bottom20'>
                <View>
                    <Input type='text'
                           placeholder='请输入关键词'
                           onInput={(e) => {
                               clearTimeout(searchInv)
                               searchInv = setTimeout(()=> {
                                   console.log('e',e.detail.value)
                                   useActionFilter({search: e.detail.value})
                               }, 300)
                           }}
                    />
                </View>
               <List length={list ? list.length : null}
                     count={count}>
                   <View className='marginX20 flex-wrap'>
                       {
                           list && list.length && list.map((device,index) => (
                               <DeviceCard key={device.name + index}
                                           device={device} />
                           ))
                       }
                   </View>
               </List>
            </View>
        )
    }
    
    

    特别提醒:Taro中一个文件只能定义一个组件



    起源地下载网 » 体验小程序 react hook——实现列表加载

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元