@fe-free/core 2.3.4 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @fe-free/core
2
2
 
3
+ ## 2.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - fix: type InfiniteList
8
+ - @fe-free/tool@2.4.1
9
+
10
+ ## 2.4.0
11
+
12
+ ### Minor Changes
13
+
14
+ - feat: add InfiniteList and sleep
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+ - @fe-free/tool@2.4.0
20
+
3
21
  ## 2.3.4
4
22
 
5
23
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fe-free/core",
3
- "version": "2.3.4",
3
+ "version": "2.4.1",
4
4
  "description": "",
5
5
  "main": "./src/index.ts",
6
6
  "author": "",
@@ -41,7 +41,7 @@
41
41
  "remark-gfm": "^4.0.1",
42
42
  "vanilla-jsoneditor": "^0.23.1",
43
43
  "zustand": "^4.5.4",
44
- "@fe-free/tool": "2.3.4"
44
+ "@fe-free/tool": "2.4.1"
45
45
  },
46
46
  "peerDependencies": {
47
47
  "@ant-design/pro-components": "2.8.9",
package/src/index.ts CHANGED
@@ -33,6 +33,8 @@ export {
33
33
  } from './form';
34
34
  export { RequestError, initErrorHandle } from './global/error';
35
35
  export { downloadInterceptor } from './global/interceptors';
36
+ export { InfiniteList } from './infinite_list';
37
+ export type { InfiniteListProps } from './infinite_list';
36
38
  export { Markdown } from './markdown';
37
39
  export { PageLayout } from './page_layout';
38
40
  export { routeTool } from './route';
@@ -0,0 +1,124 @@
1
+ import { Spin } from 'antd';
2
+ import classNames from 'classnames';
3
+ import type { ReactNode } from 'react';
4
+ import { useImperativeHandle, useRef, useState } from 'react';
5
+ import { useGlobalInfiniteScroll } from '../ahooks/use_global_infinite_scroll';
6
+
7
+ interface ActionType {
8
+ reload: () => void;
9
+ }
10
+ interface InfiniteListProps<D, P> {
11
+ request: (params: { current: number; pageSize: number } & P) => Promise<{
12
+ data: D[];
13
+ total: number;
14
+ }>;
15
+ renderItem: ({ item, index }: { item: D; index: number }) => ReactNode;
16
+ params?: P;
17
+ /** 每页数量 */
18
+ pageSize: number;
19
+ /** 定义网格布局 */
20
+ gridClassName: string;
21
+ className?: string;
22
+ actionRef?: React.Ref<ActionType | undefined>;
23
+ }
24
+
25
+ const emptyParams = {};
26
+
27
+ const InfiniteListBase = <D, P>({
28
+ request,
29
+ renderItem,
30
+ params = emptyParams as P,
31
+ actionRef,
32
+ pageSize,
33
+ gridClassName,
34
+ className,
35
+ }: InfiniteListProps<D, P>) => {
36
+ const ref = useRef<HTMLDivElement>(null);
37
+
38
+ const { data, loading, loadingMore, noMore, mutate, reload } = useGlobalInfiniteScroll(
39
+ async (p) => {
40
+ // 获得当前页面
41
+ const current = p?.nextId || 1;
42
+
43
+ const res = await request({
44
+ current,
45
+ pageSize,
46
+ ...params,
47
+ });
48
+
49
+ let hasMore = true;
50
+ // 总数少于当前页数 * 每页数量,则没有更多
51
+ if (res.total <= current * pageSize) {
52
+ hasMore = false;
53
+ }
54
+
55
+ return {
56
+ list: res.data,
57
+ nextId: hasMore ? current + 1 : undefined,
58
+ };
59
+ },
60
+ {
61
+ target: ref,
62
+ isNoMore: (d) => d?.nextId === undefined,
63
+ },
64
+ );
65
+
66
+ useImperativeHandle(actionRef, () => ({
67
+ reload: async () => {
68
+ // 没有数据,相当于重新获取
69
+ if (!data) {
70
+ return reload();
71
+ }
72
+
73
+ // 获取全部数据。因为不清楚哪个要更新。
74
+ const res = await request({
75
+ ...params,
76
+ current: 1,
77
+ pageSize,
78
+ });
79
+
80
+ // 只更新数据
81
+ data.list = res.data;
82
+
83
+ mutate({
84
+ ...data,
85
+ });
86
+ },
87
+ }));
88
+
89
+ return (
90
+ <div ref={ref} className={classNames('h-full overflow-y-auto', className)}>
91
+ {loading && (
92
+ <div className="flex h-full w-full items-center justify-center">
93
+ <Spin />
94
+ </div>
95
+ )}
96
+ {!loading && (
97
+ <div className={classNames('grid', gridClassName)}>
98
+ {data?.list?.map((item, index) => {
99
+ return <div key={index}>{renderItem({ item, index })}</div>;
100
+ })}
101
+ </div>
102
+ )}
103
+ <div className="flex w-full items-center justify-center">
104
+ {noMore && <div className="my-5 text-center text-desc">没有更多数据</div>}
105
+ {loadingMore && <div className="my-5 text-center text-desc">加载更多数据中...</div>}
106
+ </div>
107
+ </div>
108
+ );
109
+ };
110
+
111
+ function InfiniteList<D, P>(props: InfiniteListProps<D, P>) {
112
+ const [reloadCount, setReloadCount] = useState(0);
113
+
114
+ useImperativeHandle(props.actionRef, () => ({
115
+ reload: () => {
116
+ setReloadCount((prev) => prev + 1);
117
+ },
118
+ }));
119
+
120
+ return <InfiniteListBase key={reloadCount} {...props} />;
121
+ }
122
+
123
+ export { InfiniteList };
124
+ export type { InfiniteListProps };
@@ -0,0 +1,47 @@
1
+ import { InfiniteList } from '@fe-free/core';
2
+ import { sleep } from '@fe-free/tool';
3
+ import type { Meta, StoryObj } from '@storybook/react-vite';
4
+
5
+ const meta: Meta<typeof InfiniteList> = {
6
+ title: '@fe-free/core/InfiniteList',
7
+ component: InfiniteList,
8
+ tags: ['autodocs'],
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component: '无线滚动列表',
13
+ },
14
+ },
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+
20
+ type Story = StoryObj<typeof InfiniteList>;
21
+
22
+ export const Resolve: Story = {
23
+ render: () => {
24
+ return (
25
+ <div className="h-[500px]">
26
+ <InfiniteList
27
+ request={async ({ current, pageSize }) => {
28
+ await sleep(500);
29
+ return {
30
+ data: new Array(pageSize).fill(0).map((_, index) => index + (current - 1) * pageSize),
31
+ total: 100,
32
+ };
33
+ }}
34
+ renderItem={({ item }) => {
35
+ return (
36
+ <div className="p-2">
37
+ <div className="h-[100px] bg-red-500">item{item}</div>
38
+ </div>
39
+ );
40
+ }}
41
+ pageSize={20}
42
+ gridClassName="grid-cols-3"
43
+ />
44
+ </div>
45
+ );
46
+ },
47
+ };