diff --git a/src/app/(main)/character/[id]/chat/Main/actions/index.tsx b/src/app/(main)/character/[id]/chat/Main/actions/index.tsx deleted file mode 100644 index e0031f7..0000000 --- a/src/app/(main)/character/[id]/chat/Main/actions/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -'use client'; -import { - GenerateInputIcon, - PhoneCallIcon, - PortraitModeIcon, -} from '@/assets/chatacter'; -import { useChatStore } from '../../store'; -import IconFont from '@/components/ui/iconFont'; -import { cn } from '@/lib'; -import Image from 'next/image'; - -export default function Actions() { - const isPortraitMode = useChatStore((state) => state.isPortraitMode); - const setIsPortraitMode = useChatStore((state) => state.setIsPortraitMode); - const setIsPhoneCallMode = useChatStore((state) => state.setIsPhoneCallMode); - const className = 'text-[#0066FF] cursor-pointer hover:text-[#4269D6]'; - - const suggestMessages = [ - 'The threads of fate intertwine once more...The threads of fate intert', - 'The threads of fate intertwine once more.', - 'The threads of fate intertwine once more.', - ]; - - return ( -
= { + index: number; + limit: number; + query: Q; +}; + +type PropsType= { + queryKey: string; + defaultQuery?: Q; + defaultIndex?: number; + limit?: number; + isRowSame?: (d: T, n: T) => boolean; +}; + +type RequestType = ( + params: ParamsType +) => Promise<{ rows: T[]; total: number } | undefined>; + +type UseInfiniteScrollValue= { + query: Q; + onLoadMore: () => void; + onSearch: (query: Q) => void; + dataSource: T[]; + total: number; + // 是否正在加载第一页,包括 初始化加载 和 参数改变时加载 + isFirstLoading: boolean; + isLoadingMore: boolean; + noMoreData: boolean; +}; + +type DataType = { + rows: T[]; + total: number; + index: number; +}; + +const useSmartInfiniteQuery = ( + request: RequestType , + props: PropsType +): UseInfiniteScrollValue => { + const { + queryKey, + defaultQuery, + defaultIndex = 1, + limit = 20, + isRowSame = (d, n) => { + return (d as any)?.id === (n as any)?.id; + }, + } = props; + const [query, setQuery] = useState (defaultQuery as Q); + const index = useRef(defaultIndex); + + // 判断第一页数据和缓存中的第一页数据是否相等 + const isSameData = useMemoizedFn( + (prevData: DataType , result: Omit , 'index'>) => { + // 没有缓存,必不相等 + if (prevData.total <= 0 || !prevData.rows?.length) { + return false; + } + // 如果第一个元素相等,则认为数据相等(实际上并不一定) + if (!isRowSame(prevData.rows[0], result?.rows[0])) { + return false; + } + return true; + } + ); + + const { data, refetch, isFetching } = useQuery({ + queryKey: [queryKey, query], + placeholderData: keepPreviousData, + queryFn: async ({ client }) => { + const params = { + index: index.current, + limit, + query, + }; + const result = await request(params); + const prevData = (client.getQueryData([ + queryKey, + query, + ]) as DataType ) ?? { + rows: [], + total: 0, + index: 1, + }; + + // 如果是第一页 + if (params.index === defaultIndex) { + // 第一页数据和缓存中相等 + if (isSameData(prevData, result!)) { + // 更新索引 + index.current = prevData.index; + // 直接返回缓存里的 + return prevData; + } else { + // 第一页数据和缓存中不等, 返回新的数据 + return { + total: result?.total || 0, + rows: result?.rows || [], + index: params.index, + }; + } + } + + // 不是第一页, 返回合并后的数据 + return { + total: result?.total || 0, + rows: [...(prevData?.rows || []), ...(result?.rows || [])], + index: params.index, + }; + }, + }); + + const { run: onLoadMore } = useDebounceFn( + () => { + if (isFetching) return; + index.current = index.current + 1; + refetch(); + }, + { + wait: 300, + maxWait: 500, + } + ); + + const onSearch = useMemoizedFn((query: Q) => { + index.current = defaultIndex; + setQuery(query); + }); + + return { + query, + onLoadMore, + onSearch, + dataSource: data?.rows || [], + total: data?.total || 0, + isFirstLoading: isFetching && index.current === defaultIndex, + isLoadingMore: isFetching && index.current > defaultIndex, + noMoreData: data?.total === data?.rows?.length && !isFetching, + }; +}; + +export default useSmartInfiniteQuery; diff --git a/src/layouts/Providers/IntlProvider.tsx b/src/layouts/Providers/IntlProvider.tsx index 3c104fb..30f3810 100644 --- a/src/layouts/Providers/IntlProvider.tsx +++ b/src/layouts/Providers/IntlProvider.tsx @@ -33,12 +33,10 @@ interface IntlProviderProps { } function setLocaleToCookie(locale: Locale) { - if (typeof window === 'undefined') return; Cookies.set('locale', locale, { expires: 365, path: '/' }); } function getLocaleFromCookie(): Locale { - if (typeof window === 'undefined') return 'en'; const cookieLocale = Cookies.get('locale') as Locale | undefined; if (cookieLocale && (cookieLocale === 'zh' || cookieLocale === 'en')) { return cookieLocale;