103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
|
|
/**
|
||
|
|
* 帖子相关 React Hooks
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { useCallback, useEffect, useState } from 'react';
|
||
|
|
import { usePostManagerStore } from './postStore';
|
||
|
|
import { postManager } from './PostManager';
|
||
|
|
import type { Post } from '../../types';
|
||
|
|
import { POST_LIST_PAGE_SIZE } from '../postListSources';
|
||
|
|
import type { PostListTab } from '../postListSources';
|
||
|
|
|
||
|
|
// ==================== usePostList ====================
|
||
|
|
|
||
|
|
export interface UsePostListResult {
|
||
|
|
posts: Post[];
|
||
|
|
isLoading: boolean;
|
||
|
|
refresh: () => Promise<void>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取帖子列表 hook
|
||
|
|
*/
|
||
|
|
export function usePostList(
|
||
|
|
type: PostListTab = 'hot',
|
||
|
|
page = 1,
|
||
|
|
pageSize = POST_LIST_PAGE_SIZE
|
||
|
|
): UsePostListResult {
|
||
|
|
const posts = usePostManagerStore(state => {
|
||
|
|
const key = `list:${type}:${page}:${pageSize}`;
|
||
|
|
return state.listsMap.get(key)?.data ?? [];
|
||
|
|
});
|
||
|
|
const isLoading = usePostManagerStore(state => {
|
||
|
|
const key = `list:${type}:${page}:${pageSize}`;
|
||
|
|
return state.loadingListKeys.has(key);
|
||
|
|
});
|
||
|
|
const [hasFetched, setHasFetched] = useState(false);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!hasFetched) {
|
||
|
|
setHasFetched(true);
|
||
|
|
usePostManagerStore.getState().setLoadingList(type, page, pageSize, true);
|
||
|
|
postManager.getPosts(type, page, pageSize).finally(() => {
|
||
|
|
usePostManagerStore.getState().setLoadingList(type, page, pageSize, false);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}, [type, page, pageSize, hasFetched]);
|
||
|
|
|
||
|
|
const refresh = useCallback(async () => {
|
||
|
|
usePostManagerStore.getState().setLoadingList(type, page, pageSize, true);
|
||
|
|
try {
|
||
|
|
await postManager.getPosts(type, page, pageSize, true);
|
||
|
|
} finally {
|
||
|
|
usePostManagerStore.getState().setLoadingList(type, page, pageSize, false);
|
||
|
|
}
|
||
|
|
}, [type, page, pageSize]);
|
||
|
|
|
||
|
|
return { posts, isLoading, refresh };
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==================== usePostDetail ====================
|
||
|
|
|
||
|
|
export interface UsePostDetailResult {
|
||
|
|
post: Post | null;
|
||
|
|
isLoading: boolean;
|
||
|
|
refresh: () => Promise<Post | null>;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取帖子详情 hook
|
||
|
|
*/
|
||
|
|
export function usePostDetail(postId: string | undefined | null): UsePostDetailResult {
|
||
|
|
const post = usePostManagerStore(state =>
|
||
|
|
postId ? (state.detailsMap.get(postId)?.data ?? null) : null
|
||
|
|
);
|
||
|
|
const isLoading = usePostManagerStore(state =>
|
||
|
|
postId ? state.loadingDetailIds.has(postId) : false
|
||
|
|
);
|
||
|
|
const [hasFetched, setHasFetched] = useState(false);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!postId) return;
|
||
|
|
if (!hasFetched) {
|
||
|
|
setHasFetched(true);
|
||
|
|
usePostManagerStore.getState().setLoadingDetail(postId, true);
|
||
|
|
postManager.getPostDetail(postId).finally(() => {
|
||
|
|
usePostManagerStore.getState().setLoadingDetail(postId, false);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}, [postId, hasFetched]);
|
||
|
|
|
||
|
|
const refresh = useCallback(async () => {
|
||
|
|
if (!postId) return null;
|
||
|
|
usePostManagerStore.getState().setLoadingDetail(postId, true);
|
||
|
|
try {
|
||
|
|
return await postManager.getPostDetail(postId, true);
|
||
|
|
} finally {
|
||
|
|
usePostManagerStore.getState().setLoadingDetail(postId, false);
|
||
|
|
}
|
||
|
|
}, [postId]);
|
||
|
|
|
||
|
|
return { post, isLoading, refresh };
|
||
|
|
}
|