137 lines
4.0 KiB
TypeScript
137 lines
4.0 KiB
TypeScript
|
|
/**
|
|||
|
|
* 用户相关 React Hooks
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { useCallback, useEffect, useState } from 'react';
|
|||
|
|
import { useUserManagerStore } from './userStore';
|
|||
|
|
import { userManager } from './UserManager';
|
|||
|
|
import type { UserDTO } from '../../types/dto';
|
|||
|
|
|
|||
|
|
// ==================== useCurrentUser ====================
|
|||
|
|
|
|||
|
|
export interface UseCurrentUserResult {
|
|||
|
|
user: UserDTO | null;
|
|||
|
|
isLoading: boolean;
|
|||
|
|
refresh: () => Promise<UserDTO | null>;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取当前用户 hook
|
|||
|
|
* 自动加载,支持缓存和后台刷新
|
|||
|
|
*/
|
|||
|
|
export function useCurrentUser(): UseCurrentUserResult {
|
|||
|
|
const user = useUserManagerStore(state => state.currentUser);
|
|||
|
|
const isLoading = useUserManagerStore(state => state.isLoadingCurrentUser);
|
|||
|
|
const [hasFetched, setHasFetched] = useState(false);
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (!hasFetched) {
|
|||
|
|
setHasFetched(true);
|
|||
|
|
useUserManagerStore.getState().setLoadingCurrentUser(true);
|
|||
|
|
userManager.getCurrentUser().finally(() => {
|
|||
|
|
useUserManagerStore.getState().setLoadingCurrentUser(false);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}, [hasFetched]);
|
|||
|
|
|
|||
|
|
const refresh = useCallback(async () => {
|
|||
|
|
useUserManagerStore.getState().setLoadingCurrentUser(true);
|
|||
|
|
try {
|
|||
|
|
return await userManager.getCurrentUser(true);
|
|||
|
|
} finally {
|
|||
|
|
useUserManagerStore.getState().setLoadingCurrentUser(false);
|
|||
|
|
}
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
return { user, isLoading, refresh };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== useUser ====================
|
|||
|
|
|
|||
|
|
export interface UseUserResult {
|
|||
|
|
user: UserDTO | null;
|
|||
|
|
isLoading: boolean;
|
|||
|
|
refresh: () => Promise<UserDTO | null>;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 根据 ID 获取用户 hook
|
|||
|
|
* 自动加载,支持缓存和后台刷新
|
|||
|
|
*/
|
|||
|
|
export function useUser(userId: string | undefined | null): UseUserResult {
|
|||
|
|
const user = useUserManagerStore(state =>
|
|||
|
|
userId ? (state.usersMap.get(userId)?.data ?? null) : null
|
|||
|
|
);
|
|||
|
|
const isLoading = useUserManagerStore(state =>
|
|||
|
|
userId ? state.loadingUserIds.has(userId) : false
|
|||
|
|
);
|
|||
|
|
const [hasFetched, setHasFetched] = useState(false);
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
if (!userId) return;
|
|||
|
|
if (!hasFetched) {
|
|||
|
|
setHasFetched(true);
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(userId, true);
|
|||
|
|
userManager.getUserById(userId).finally(() => {
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(userId, false);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}, [userId, hasFetched]);
|
|||
|
|
|
|||
|
|
const refresh = useCallback(async () => {
|
|||
|
|
if (!userId) return null;
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(userId, true);
|
|||
|
|
try {
|
|||
|
|
return await userManager.getUserById(userId, true);
|
|||
|
|
} finally {
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(userId, false);
|
|||
|
|
}
|
|||
|
|
}, [userId]);
|
|||
|
|
|
|||
|
|
return { user, isLoading, refresh };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== useUsers ====================
|
|||
|
|
|
|||
|
|
export interface UseUsersResult {
|
|||
|
|
getUser: (id: string) => UserDTO | null;
|
|||
|
|
refreshUser: (id: string) => Promise<UserDTO | null>;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 多用户获<EFBFBD><EFBFBD>?hook
|
|||
|
|
* 用于批量获取多个用户信息
|
|||
|
|
*/
|
|||
|
|
export function useUsers(userIds: string[]): UseUsersResult {
|
|||
|
|
const usersMap = useUserManagerStore(state => state.usersMap);
|
|||
|
|
const loadingUserIds = useUserManagerStore(state => state.loadingUserIds);
|
|||
|
|
const [fetchedIds, setFetchedIds] = useState<Set<string>>(new Set());
|
|||
|
|
|
|||
|
|
useEffect(() => {
|
|||
|
|
userIds.forEach(id => {
|
|||
|
|
if (!fetchedIds.has(id) && !loadingUserIds.has(id)) {
|
|||
|
|
setFetchedIds(prev => new Set(prev).add(id));
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(id, true);
|
|||
|
|
userManager.getUserById(id).finally(() => {
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(id, false);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}, [userIds, fetchedIds, loadingUserIds]);
|
|||
|
|
|
|||
|
|
const getUser = useCallback((id: string) => {
|
|||
|
|
return usersMap.get(id)?.data ?? null;
|
|||
|
|
}, [usersMap]);
|
|||
|
|
|
|||
|
|
const refreshUser = useCallback(async (id: string) => {
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(id, true);
|
|||
|
|
try {
|
|||
|
|
return await userManager.getUserById(id, true);
|
|||
|
|
} finally {
|
|||
|
|
useUserManagerStore.getState().setLoadingUser(id, false);
|
|||
|
|
}
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
return { getUser, refreshUser };
|
|||
|
|
}
|