diff --git a/src/application/types.ts b/src/application/types.ts index 93ea702c..c053a89a 100644 --- a/src/application/types.ts +++ b/src/application/types.ts @@ -1196,7 +1196,7 @@ export interface MentionablePerson { name: string; role: number; - uuid: string; + person_id: string; invited: boolean; last_mentioned_at: string | null; } diff --git a/src/components/app/app.hooks.tsx b/src/components/app/app.hooks.tsx index e8caf7b2..6cb0f56a 100644 --- a/src/components/app/app.hooks.tsx +++ b/src/components/app/app.hooks.tsx @@ -46,6 +46,7 @@ import { AppOverlayProvider } from '@/components/app/app-overlay/AppOverlayProvi import RequestAccess from '@/components/app/landing-pages/RequestAccess'; import { AFConfigContext, useService } from '@/components/main/app.hooks'; import { findAncestors, findView, findViewByLayout } from '@/components/_shared/outline/utils'; +import { createDeduplicatedNoArgsRequest } from '@/utils/deduplicateRequest'; const ViewModal = React.lazy(() => import('@/components/app/ViewModal')); @@ -1052,7 +1053,9 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { ); const mentionableUsersRef = useRef([]); - const loadMentionableUsers = useCallback(async () => { + + // 原始的请求函数 + const _loadMentionableUsers = useCallback(async () => { if (!currentWorkspaceId || !service) { throw new Error('No workspace or service found'); } @@ -1068,15 +1071,19 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { } }, [currentWorkspaceId, service]); + const loadMentionableUsers = useMemo( + () => createDeduplicatedNoArgsRequest(_loadMentionableUsers), + [_loadMentionableUsers] + ); + useEffect(() => { void loadMentionableUsers(); }, [loadMentionableUsers]); const getMentionUser = useCallback( async (uuid: string) => { - console.log('mentionableUsers', mentionableUsersRef.current); if (mentionableUsersRef.current.length > 0) { - const user = mentionableUsersRef.current.find((user) => user.uuid === uuid); + const user = mentionableUsersRef.current.find((user) => user.person_id === uuid); if (user) { return user; @@ -1086,7 +1093,7 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { try { const res = await loadMentionableUsers(); - return res.find((user) => user.uuid === uuid); + return res.find((user: MentionablePerson) => user.person_id === uuid); } catch (e) { return Promise.reject(e); } diff --git a/src/utils/deduplicateRequest.ts b/src/utils/deduplicateRequest.ts new file mode 100644 index 00000000..be0ae7a3 --- /dev/null +++ b/src/utils/deduplicateRequest.ts @@ -0,0 +1,40 @@ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function createDeduplicatedRequest Promise>( + requestFn: T, + keyGenerator?: (...args: Parameters) => string +): T { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const pendingRequests = new Map>(); + + return ((...args: Parameters) => { + const key = keyGenerator ? keyGenerator(...args) : JSON.stringify(args); + + if (pendingRequests.has(key)) { + return pendingRequests.get(key)!; + } + + const promise = requestFn(...args).finally(() => { + pendingRequests.delete(key); + }); + + pendingRequests.set(key, promise); + + return promise; + }) as T; +} + +export function createDeduplicatedNoArgsRequest(requestFn: () => Promise): () => Promise { + let pendingRequest: Promise | null = null; + + return () => { + if (pendingRequest) { + return pendingRequest; + } + + pendingRequest = requestFn().finally(() => { + pendingRequest = null; + }); + + return pendingRequest; + }; +}