React 列表定时轮询刷新+滚动加载

1、安装依赖
npm i antd
npm i react-infinite-scroll-component
2、DataList.tsx
import React, { useEffect, useRef } from "react";
import { Spin } from "antd";
import InfiniteScroll from "react-infinite-scroll-component";
import { useListStore } from "./store/list";
import { getDataList, refreshDataList } from "./store/list/action";
export default function DataList() {
const { dataList, total, getListLoading, hasMore, refreshLoading } =
useListStore();
const clearDataListTimer = useRef<() => void>(() => { });
const init = async () => {
await getDataList();
const dataListTimer = await refreshDataList();
clearDataListTimer.current = () => {
clearInterval(dataListTimer);
};
};
useEffect(() => {
(async () => {
await init();
})();
return () => {
clearDataListTimer.current();
};
}, []);
return (
<div>
<h2>Data List total: {total}</h2>
{refreshLoading && <p>Refreshing...</p>}
{hasMore && !getListLoading && (
<button onClick={getDataList}>Click:Load More</button>
)}
<div id='list' style={{ height: "400px", overflowY: "auto" }}>
<Spin spinning={getListLoading}>
<InfiniteScroll
dataLength={dataList.length}
next={getDataList}
hasMore={!!hasMore}
loader={null}
scrollableTarget={"list"}
>
{dataList.map((item) => (
<div key={item.id}>
<h3>{item.name}</h3>
<p>{item.description}</p>
</div>
))}
</InfiniteScroll>
{!dataList.length && <p>No data</p>}
</Spin>
</div>
</div>
);
}
2、store\list
-- index.ts
import { create } from 'zustand';
export interface IListState {
readonly dataList: ReadonlyArray<any>;
readonly page: {
pageNum: number; // 页码
pageSize: number; // 每页数量
};
readonly total: number;
readonly getListLoading: boolean;
readonly hasMore: boolean;
readonly refreshLoading: boolean;
}
const initialState: IListState = {
dataList: [],
page: {
pageNum: 0,
pageSize: 10,
},
total: 0,
getListLoading: false,
hasMore: true,
refreshLoading: false,
};
export const useListStore = create<IListState>(
() => initialState,
);
3、store\list
-- action.ts
import { useListStore } from ".";
import { getList } from "../../api";
import { loopHandler } from "../../utils";
const { setState, getState } = useListStore;
/**
* 获取dataList
*/
export const getDataList = async () => {
try {
const { dataList, page } = getState();
const newPage = { ...page, pageNum: page.pageNum + 1 };
setState({ getListLoading: true });
const { list, total_size } = await getList(
newPage.pageNum,
newPage.pageSize,
);
if (Array.isArray(list)) {
const newDataList = [...dataList, ...list];
const hasMore =
total_size > newDataList.length;
setState({
dataList: newDataList,
total: total_size,
hasMore,
page: { ...newPage },
});
}
} catch (error) {
console.error('getDataList error.', error);
}
setState({ getListLoading: false });
};
/**
* 刷新所有dataList
*/
const loopRefreshDataList = async () => {
const { page } = getState();
const curPage = page.pageNum || 1;
const dataList = [];
let newTotal = 0;
let lastPage = curPage;
setState({ refreshLoading: true });
try {
for (let i = 1; i <= curPage; i++) {
const { list, total_size } =
await getList(i, page.pageSize);
if (!list) {
break;
}
newTotal = total_size;
dataList.push(...list);
if (
list.length <= page.pageSize &&
dataList.length === total_size
) {
lastPage = i;
break;
}
}
const hasMore = newTotal > dataList.length;
setState({
dataList,
hasMore,
page: { ...page, pageNum: lastPage },
total: newTotal,
});
} catch (error) {
console.error('loopRefreshDataList error.', error);
}
setState({ refreshLoading: false });
};
// 每三十秒刷新dataList
export const refreshDataList = async () => {
const loopInterval = 30 * 1000;
return await loopHandler(loopRefreshDataList, loopInterval)();
};
4、utils.ts
export const loopHandler = (
fn: (...args: any) => Promise<any>,
delay: number,
) => {
let timer: any = null;
return () => {
if (timer) {
clearInterval(timer);
}
timer = setInterval(async () => {
await fn();
}, delay);
return timer;
};
};
export const sleep = async (delay: number) =>
await new Promise((resolve) => setTimeout(resolve, delay));
5、api.ts
import { sleep } from "./utils";
interface PaginatedResponse<T> {
page: number;
page_size: number;
total_size: number;
list: T[];
}
export const getList = async (
page: number,
pageSize: number,
): Promise<PaginatedResponse<any>> => {
// return await request<PaginatedResponse<any>>(
// `/get_list`,
// { page: page, page_size: pageSize },
// );
// 模拟虚拟数据
await sleep(500)
const list = Array.from({ length: pageSize }, (_, index) => ({
id: `item-${(page - 1) * pageSize + index + 1}`,
name: `Item ${(page - 1) * pageSize + index + 1}`,
description: `This is item ${(page - 1) * pageSize + index + 1}`,
}));
const total_size = 100; // 模拟总数据量为 100
return {
page,
page_size: pageSize,
total_size,
list,
};
}
本文来自博客园,作者:苏沐~,转载请注明原文链接:https://www.cnblogs.com/sumu80/p/19057326

浙公网安备 33010602011771号