二次封装react无限加载组件(一)

写在前面

  • 本组件使用了antd组件库里提供的List组件,需要对antd有所了解呀,小伙伴们

看了一下文档,也看了相关代码,官方给出的List无限加载组件实在是不跟恭维呀!一团乱麻,根本没法维护,也不能复用。

开始二次封装之旅

需要掌握的技能:

  • dva的使用。
  • hook
  • 函数组件

在这里我把List组件封装成一个无状态函数组件(无状态组件有明显优势),也先贴下组件代码

import React, { Component, useState,  } from 'react';
import { Skeleton, List, message, Avatar, Spin, Icon } from 'antd';
import { Link } from 'dva/router';
import { connect } from 'dva';

import WindowScroller from 'react-virtualized/dist/commonjs/WindowScroller';
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import VList from 'react-virtualized/dist/commonjs/List';
import InfiniteLoader from 'react-virtualized/dist/commonjs/InfiniteLoader';

import styles from './index.module.less';
import {classNames} from '../../utils'

const IconText = ({ type, text }) => (
  <span>
    <Icon type={type} style={{ marginRight: 8 }} />
    {text}
  </span>
);

function PullLoadList({
    className,
    dataSource = [],
    fetchData,
    loading = false,
    isEnd = false,
}){
    const loadedRowsMap = {};

    const handleInfiniteOnLoad = ({ startIndex, stopIndex }) => {

        for (let i = startIndex; i <= stopIndex; i++) {
        // 1 means loading
            loadedRowsMap[i] = 1;
        }

        // 到底了
        if(isEnd) return;

        //加载数据
        fetchData();
    };

    const isRowLoaded = ({ index }) => !!loadedRowsMap[index];

    const renderItem = ({ index, key, style }) => {
        const item = dataSource[index];
        return (
            <List.Item
                key={key}
                style = {style}
            >
                <div className={styles.content_text}>
                    <div className={styles.left_box}>
                        <Link  to={`/details/${index}`} className={styles.title}>{item.title}</Link>
                        <div className={styles.content}>
                            {item.content}
                        </div>
                        <div className={styles.actions}>
                            <IconText type="star-o" text={item.star} key="list-vertical-star-o" />
                            <IconText type="like-o" text={item.like} key="list-vertical-like-o" />
                            <span>{item.date}</span>
                        </div>
                    </div>
                    <div className={styles.right_box}>
                        <img
                        alt="logo"
                        src={item.image}
                    />
                    </div>
                </div>
            </List.Item>
        );
    };

    const vlist = ({ height, isScrolling, onChildScroll, scrollTop, onRowsRendered, width }) => (
        <VList
            autoHeight
            height={height}
            isScrolling={isScrolling}
            onScroll={onChildScroll}
            overscanRowCount={1}
            rowCount={dataSource.length}
            rowHeight={200}
            rowRenderer={renderItem}
            onRowsRendered={onRowsRendered}
            scrollTop={scrollTop}
            width={width}
        />
    );
    const autoSize = ({ height, isScrolling, onChildScroll, scrollTop, onRowsRendered }) => (
        <AutoSizer disableHeight>
            {({ width }) =>
                vlist({
                    height,
                    isScrolling,
                    onChildScroll,
                    scrollTop,
                    onRowsRendered,
                    width,
                })
            }
        </AutoSizer>
    );

    const infiniteLoader = ({ height, isScrolling, onChildScroll, scrollTop }) => (
        <InfiniteLoader
            isRowLoaded={isRowLoaded}
            loadMoreRows={handleInfiniteOnLoad}
            rowCount={dataSource.length}
        >
            {({ onRowsRendered }) =>
                autoSize({
                    height,
                    isScrolling,
                    onChildScroll,
                    scrollTop,
                    onRowsRendered,
                })
            }
        </InfiniteLoader>
    );

    return (
        <div className={styles.pullloadlist}>
            {
                dataSource.length > 0 ?
                <List 
                    itemLayout="vertical" 
                    size="large" 
                    className={classNames(className)}>
                    <WindowScroller>{infiniteLoader}</WindowScroller>
                </List> : ''
            }

            <div className={styles.loading}>
                {isEnd && !loading ? 
                    <span>已经到底了</span> : 
                    <span>正在加载... <Spin className="demo-loading" /></span>
                }
            </div>
        </div>
        
    );
}

export default PullLoadList;

使用方法如下

  • 需要传入如下参数,这里对hook不了解的小伙伴,可以自行了解下 hook
// 数据源
    const {dataSource, pagination} = list;
    // 当前页数
    const [count, setCount] = useState(pagination.currentPage || 1);
    // loading状态
    const [loading, setLoading] = useState(false);
    // 是否还有数据
    const [isEnd, setIsEnd] = useState(false);
    // 组件参数
    const listProps = {
        isEnd: isEnd,
        loading: loading,
        dataSource : dataSource,
        fetchData : () =>{
            setLoading(true);
            // 更新当前页数
            setCount(count+1)
            // 异步加载数据
            dispatch({
                type: 'list/effect:init',
                payload: {
                    currentPage: count
                }
            }).then(result  => {
                console.log(pagination.total)
                if(count >= pagination.totalPage){
                    setIsEnd(true);
                }
                setLoading(false);
            });
        }
    }

  • 使用组件
<PullLoadList className={styles.list} {...listProps}/>

附一张加载图

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容

  • 第一天主要是跟你挑行业,说打工的辛酸,这第二天干啥呢?上午的时候,来了一个其它寝室的领导,别人都叫他毛哥,...
    行走的芭蕉1阅读 220评论 0 1
  • 今天做的冥想练习是,用双手的指尖互相触碰,营造出一个能量空间,然后,自己慢慢的往内心深处探索。 通过这个练习,让我...
    快乐的熙爷阅读 1,391评论 0 1