UNPKG

2.81 kBJavaScriptView Raw
1import React, { useEffect, useReducer } from "react";
2import { LoadingOutlined } from "@ant-design/icons";
3import { useDebounceFn } from "ahooks";
4import http from "@script/http";
5const CACHES = {}; // 数据缓存
6
7const initState = {
8 data: [],
9 loading: false,
10 hasMore: true,
11};
12const reducer = (state, action) => {
13 return { ...state, ...action };
14};
15/**
16 * ----------------------------------------
17 * 加载数据
18 * @param {String} url - 加载地址
19 * @param {Function} ondata - 数据回调
20 * @param {Array} [deps] - 变化依赖
21 * @param {Number} [size = 10] - 加载数量
22 * @param {String} [cached = ''] - 是否缓存数据, 设置缓存数据的key, 并保证唯一性
23 * ----------------------------------------
24 */
25export default function FetchMore({
26 url,
27 ondata,
28 deps,
29 size = 10,
30 cached = "",
31}) {
32 const [state, dispatch] = useReducer(reducer, initState);
33
34 const { run } = useDebounceFn(() => fetcher(true), {
35 wait: 500,
36 leading: true,
37 trailing: false,
38 });
39
40 const fetcher = async isAppend => {
41 const params = { size };
42 const len = state.data.length;
43
44 if (len > 0 && isAppend === true) {
45 params.last = state.data[len - 1]._id;
46 }
47 dispatch({ loading: true });
48
49 const res = await http.get(url, { params });
50 const data = isAppend ? state.data.concat(res) : res;
51 const hasMore = res.length === size;
52 dispatch({ loading: false, data, hasMore });
53 if (cached) {
54 CACHES[cached] = data;
55 }
56 ondata(data);
57 };
58
59 useEffect(() => {
60 if (cached && CACHES[cached]?.length > 0) {
61 dispatch({ data: CACHES[cached], hasMore: true });
62 ondata(CACHES[cached]);
63 } else {
64 fetcher(false);
65 }
66 }, [].concat(deps));
67
68 return <Loading onClick={run} state={state}></Loading>;
69}
70
71/**
72 * ----------------------------------------
73 * 加载更多
74 * ----------------------------------------
75 */
76const Loading = ({ state, onClick }) => {
77 if (state.loading) {
78 return (
79 <LoadingText>
80 <LoadingOutlined style={{ marginRight: "5px" }} />
81 <span>正在加载</span>
82 </LoadingText>
83 );
84 }
85 if (state.hasMore)
86 return (
87 <LoadingText>
88 <span onClick={onClick} style={{ cursor: "pointer" }}>
89 加载更多
90 </span>
91 </LoadingText>
92 );
93 return (
94 <LoadingText style={{ color: "#c1c1c1" }}>- 没有更多数据了 -</LoadingText>
95 );
96};
97
98const LoadingText = ({ style, children, ...rest }) => {
99 return (
100 <div
101 style={{
102 textAlign: "center",
103 padding: 0,
104 paddingTop: "25px",
105 paddingBottom: "40px",
106 letterSpacing: "1px",
107 color: "gray",
108 fontSize: "13px",
109 clear: "both",
110 ...style,
111 }}
112 {...rest}
113 >
114 {children}
115 </div>
116 );
117};