refactor(core): introduce EventBus and refactor store infrastructure
- Add EventBus for decoupled event-driven communication between services - Add EventSubscriber component for centralized event handling - Add requestDedupe utility for shared request deduplication - Refactor api/wsService to use eventBus instead of direct router navigation - Extract MessageMapper.toCachedMessages for consistent message mapping - Remove deprecated BaseManager and CacheBus classes - Improve @mention rendering with memberMap support in segment rendering - Update hooks to use useRef instead of useState for fetch tracking
This commit is contained in:
@@ -1,13 +1,8 @@
|
||||
/**
|
||||
* 用户相关 React Hooks
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useUserManagerStore } from './userStore';
|
||||
import { userManager } from './UserManager';
|
||||
import type { UserDTO } from '../../types/dto';
|
||||
|
||||
// ==================== useCurrentUser ====================
|
||||
import { useAuthStore } from '../authStore';
|
||||
|
||||
export interface UseCurrentUserResult {
|
||||
user: UserDTO | null;
|
||||
@@ -15,24 +10,30 @@ export interface UseCurrentUserResult {
|
||||
refresh: () => Promise<UserDTO | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获å<C2B7>–当å‰<C3A5>用户 hook
|
||||
* è‡ªåŠ¨åŠ è½½ï¼Œæ”¯æŒ<C3A6>缓å˜å’Œå<C592>Žå<C5BD>°åˆ·æ–°
|
||||
*/
|
||||
export function useCurrentUser(): UseCurrentUserResult {
|
||||
const user = useUserManagerStore(state => state.currentUser);
|
||||
const isLoading = useUserManagerStore(state => state.isLoadingCurrentUser);
|
||||
const [hasFetched, setHasFetched] = useState(false);
|
||||
const lastFetchedRef = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasFetched) {
|
||||
setHasFetched(true);
|
||||
const authUser = useAuthStore.getState().currentUser;
|
||||
const userId = authUser?.id;
|
||||
if (userId && lastFetchedRef.current !== userId) {
|
||||
lastFetchedRef.current = userId;
|
||||
useUserManagerStore.getState().setLoadingCurrentUser(true);
|
||||
userManager.getCurrentUser().finally(() => {
|
||||
useUserManagerStore.getState().setLoadingCurrentUser(false);
|
||||
});
|
||||
}
|
||||
}, [hasFetched]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return useAuthStore.subscribe((state, prev) => {
|
||||
if (!state.currentUser && prev.currentUser) {
|
||||
lastFetchedRef.current = null;
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
useUserManagerStore.getState().setLoadingCurrentUser(true);
|
||||
@@ -46,18 +47,12 @@ export function useCurrentUser(): UseCurrentUserResult {
|
||||
return { user, isLoading, refresh };
|
||||
}
|
||||
|
||||
// ==================== useUser ====================
|
||||
|
||||
export interface UseUserResult {
|
||||
user: UserDTO | null;
|
||||
isLoading: boolean;
|
||||
refresh: () => Promise<UserDTO | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* æ ¹æ<C2B9>® ID 获å<C2B7>–用户 hook
|
||||
* è‡ªåŠ¨åŠ è½½ï¼Œæ”¯æŒ<C3A6>缓å˜å’Œå<C592>Žå<C5BD>°åˆ·æ–°
|
||||
*/
|
||||
export function useUser(userId: string | undefined | null): UseUserResult {
|
||||
const user = useUserManagerStore(state =>
|
||||
userId ? (state.usersMap.get(userId)?.data ?? null) : null
|
||||
@@ -65,18 +60,18 @@ export function useUser(userId: string | undefined | null): UseUserResult {
|
||||
const isLoading = useUserManagerStore(state =>
|
||||
userId ? state.loadingUserIds.has(userId) : false
|
||||
);
|
||||
const [hasFetched, setHasFetched] = useState(false);
|
||||
const lastFetchedRef = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!userId) return;
|
||||
if (!hasFetched) {
|
||||
setHasFetched(true);
|
||||
if (lastFetchedRef.current !== userId) {
|
||||
lastFetchedRef.current = userId;
|
||||
useUserManagerStore.getState().setLoadingUser(userId, true);
|
||||
userManager.getUserById(userId).finally(() => {
|
||||
useUserManagerStore.getState().setLoadingUser(userId, false);
|
||||
});
|
||||
}
|
||||
}, [userId, hasFetched]);
|
||||
}, [userId]);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
if (!userId) return null;
|
||||
@@ -91,33 +86,27 @@ export function useUser(userId: string | undefined | null): UseUserResult {
|
||||
return { user, isLoading, refresh };
|
||||
}
|
||||
|
||||
// ==================== useUsers ====================
|
||||
|
||||
export interface UseUsersResult {
|
||||
getUser: (id: string) => UserDTO | null;
|
||||
refreshUser: (id: string) => Promise<UserDTO | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 多用户获å<C2B7>?hook
|
||||
* 用于批é‡<C3A9>获å<C2B7>–多个用户信æ<C2A1>¯
|
||||
*/
|
||||
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());
|
||||
const fetchedIdsRef = useRef<Set<string>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
userIds.forEach(id => {
|
||||
if (!fetchedIds.has(id) && !loadingUserIds.has(id)) {
|
||||
setFetchedIds(prev => new Set(prev).add(id));
|
||||
if (!fetchedIdsRef.current.has(id) && !loadingUserIds.has(id)) {
|
||||
fetchedIdsRef.current = new Set(fetchedIdsRef.current).add(id);
|
||||
useUserManagerStore.getState().setLoadingUser(id, true);
|
||||
userManager.getUserById(id).finally(() => {
|
||||
useUserManagerStore.getState().setLoadingUser(id, false);
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [userIds, fetchedIds, loadingUserIds]);
|
||||
}, [userIds, loadingUserIds]);
|
||||
|
||||
const getUser = useCallback((id: string) => {
|
||||
return usersMap.get(id)?.data ?? null;
|
||||
@@ -133,4 +122,4 @@ export function useUsers(userIds: string[]): UseUsersResult {
|
||||
}, []);
|
||||
|
||||
return { getUser, refreshUser };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user