From 457fc8595d9a52adf6f4fd7ec343ef76fa6e3497 Mon Sep 17 00:00:00 2001 From: kyuuseiryuu Date: Fri, 13 Mar 2026 12:10:04 +0900 Subject: [PATCH] feat(components, page): club events list pagination in it's self --- src/components/ClubEventList.tsx | 87 +++++++++++++------- src/components/GameSelector/GameSelector.tsx | 34 +------- src/page/ClubEvents.tsx | 8 +- 3 files changed, 66 insertions(+), 63 deletions(-) diff --git a/src/components/ClubEventList.tsx b/src/components/ClubEventList.tsx index 7d9bf2b..cdecc47 100644 --- a/src/components/ClubEventList.tsx +++ b/src/components/ClubEventList.tsx @@ -1,30 +1,50 @@ -import { Divider, Empty, Flex, Pagination, Space, Spin, Switch, Typography } from "antd"; +import { Divider, Empty, Flex, Pagination, Skeleton, Space, Spin, Switch, Typography } from "antd"; import type { IEventInfo } from "../types"; -import { useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { EventCard } from "./EventCard"; +import { useRequest } from "ahooks"; interface Props { - events: IEventInfo[]; - loading?: boolean; - pagination?: { - page: number; - total: number; - onPageChange: (page: number) => void; - }; + clubId: string; } export const ClubEvenList = (props: Props) => { const [showAll, setShowAll] = useState(false); - const visibleEvents = useMemo(() => { - if (showAll) return props.events; - return props.events.filter(e => !e.isFinished); - }, [showAll, props.events]); - useEffect(() => { - if (!showAll && props.pagination && props.pagination.page > 1) { - props.pagination.onPageChange(1); // Reset page + const requestEvents = useRequest<{data: IEventInfo[]; total: number; }, [string, number]>( + async (clubId: string, page = 1) => { + if (!clubId) return []; + return (await fetch(`/api/events/${clubId}?page=${page}`)).json() + }, { manual: true }); + const [page, setPage] = useState(1); + const onPageChange = useCallback((page: number) => { + setPage(page); + requestEvents.runAsync(props.clubId, page); + }, [props.clubId]); + const pagination = useMemo(() => { + return { + page, + onPageChange, + total: requestEvents.data?.total ?? 0, } - }, [showAll, props]); + }, [requestEvents.data?.total, page]); + const visibleEvents = useMemo(() => { + const events = requestEvents.data?.data || []; + if (showAll) return events; + return events.filter(e => !e.isFinished); + }, [showAll, requestEvents.data?.data]); + useEffect(() => { + if (!showAll && page > 1) { + onPageChange(1); // Reset page + } + }, [showAll, onPageChange]); + useEffect(() => { + const id = setTimeout(() => { + requestEvents.run(props.clubId, 1); + setPage(1); + }, 100); + return () => clearTimeout(id); + }, [props.clubId]); return ( - + <> 显示已结束的活动 @@ -32,28 +52,37 @@ export const ClubEvenList = (props: Props) => { - {showAll && props.pagination ? ( + {showAll ? ( ) : null} - {visibleEvents.length ? visibleEvents.map(e => { + {requestEvents.loading ? ( + + + + + + ) : (<>{visibleEvents.length ? visibleEvents.map(e => { return (
); - }) : } - {showAll && props.pagination ? ( + }) : })} + + {showAll ? ( ) : null}
-
+ ); } \ No newline at end of file diff --git a/src/components/GameSelector/GameSelector.tsx b/src/components/GameSelector/GameSelector.tsx index 12ee842..72a987d 100644 --- a/src/components/GameSelector/GameSelector.tsx +++ b/src/components/GameSelector/GameSelector.tsx @@ -1,33 +1,16 @@ import { Flex, Select, Space } from 'antd'; import type React from 'react'; -import { useRequest } from 'ahooks'; import { clubs } from './clubList'; -import { useCallback, useEffect, useState } from 'react'; -import type { IEventInfo } from '../../types'; +import { useCallback, useState } from 'react'; import { ClubEvenList } from '../ClubEventList'; interface Props { } -export const GameSelector: React.FC = props => { +export const GameSelector: React.FC = () => { const [clubId, setClubId] = useState(clubs[0]?.clubId ?? ''); - const requestEvents = useRequest<{data: IEventInfo[]; total: number; }, [string, number]>( - async (clubId: string, page = 1) => { - if (!clubId) return []; - return (await fetch(`/api/events/${clubId}?page=${page}`)).json() - }, { manual: true }); const handleClubChange = useCallback(async (id: string) => { setClubId(id); - requestEvents.runAsync(id, page); - }, []); - const [page, setPage] = useState(1); - useEffect(() => { - const id = setTimeout(() => { - const clubId = clubs?.[0]?.clubId; - if (!clubId) return; - requestEvents.run(clubId, 1); - }, 100); - return () => clearTimeout(id); }, []); return ( @@ -41,18 +24,7 @@ export const GameSelector: React.FC = props => { onChange={handleClubChange} /> - { - setPage(page); - requestEvents.runAsync(clubId, page); - } - }} - /> + ); } diff --git a/src/page/ClubEvents.tsx b/src/page/ClubEvents.tsx index 3f375ad..ad44505 100644 --- a/src/page/ClubEvents.tsx +++ b/src/page/ClubEvents.tsx @@ -1,14 +1,16 @@ import { Avatar, Button, Drawer, Typography } from "antd"; import { useLoaderData } from "react-router"; import type { ClubInfo, IEventInfo } from "../types"; -import { useState } from "react"; +import { useCallback, useState } from "react"; import { ChangeBackground } from "../components/ChangeBackground"; import { ClubEvenList } from "../components/ClubEventList"; +import { useRequest } from "ahooks"; export const ClubEventsPage = () => { - const { info, events } = useLoaderData<{ + const { info, events, total } = useLoaderData<{ info: ClubInfo; events: IEventInfo[]; + total: number; }>(); const [isArticleOpen, setIsArticleOpen] = useState(false); @@ -18,7 +20,7 @@ export const ClubEventsPage = () => { {info.name} - + setIsArticleOpen(false)} placement="bottom">
{info.article}