1 | import React, { useEffect, useReducer } from "react";
|
2 | import { LoadingOutlined } from "@ant-design/icons";
|
3 | import { useDebounceFn } from "ahooks";
|
4 | import http from "@script/http";
|
5 | const CACHES = {};
|
6 |
|
7 | const initState = {
|
8 | data: [],
|
9 | loading: false,
|
10 | hasMore: true,
|
11 | };
|
12 | const reducer = (state, action) => {
|
13 | return { ...state, ...action };
|
14 | };
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export 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 |
|
76 | const 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 |
|
98 | const 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 | };
|