Commit 65238919 authored by Steven's avatar Steven

fix: react hooks order violation in MemoDetail when creating comments

Replace dynamic hook mapping with useMemoComments hook to fetch all comments
via listMemoComments API, ensuring consistent hook order across renders and
fixing page load failure after comment creation.
parent c4dfb854
...@@ -118,10 +118,17 @@ const MemoEditorImpl: React.FC<MemoEditorProps> = ({ ...@@ -118,10 +118,17 @@ const MemoEditorImpl: React.FC<MemoEditorProps> = ({
cacheService.clear(cacheService.key(currentUser?.name ?? "", cacheKey)); cacheService.clear(cacheService.key(currentUser?.name ?? "", cacheKey));
// Invalidate React Query cache to refresh memo lists across the app // Invalidate React Query cache to refresh memo lists across the app
await Promise.all([ const invalidationPromises = [
queryClient.invalidateQueries({ queryKey: memoKeys.lists() }), queryClient.invalidateQueries({ queryKey: memoKeys.lists() }),
queryClient.invalidateQueries({ queryKey: userKeys.stats() }), queryClient.invalidateQueries({ queryKey: userKeys.stats() }),
]); ];
// If this was a comment, also invalidate the comments query for the parent memo
if (parentMemoName) {
invalidationPromises.push(queryClient.invalidateQueries({ queryKey: memoKeys.comments(parentMemoName) }));
}
await Promise.all(invalidationPromises);
// Reset editor state to initial values // Reset editor state to initial values
dispatch(actions.reset()); dispatch(actions.reset());
......
...@@ -13,6 +13,7 @@ export const memoKeys = { ...@@ -13,6 +13,7 @@ export const memoKeys = {
list: (filters: Partial<ListMemosRequest>) => [...memoKeys.lists(), filters] as const, list: (filters: Partial<ListMemosRequest>) => [...memoKeys.lists(), filters] as const,
details: () => [...memoKeys.all, "detail"] as const, details: () => [...memoKeys.all, "detail"] as const,
detail: (name: string) => [...memoKeys.details(), name] as const, detail: (name: string) => [...memoKeys.details(), name] as const,
comments: (name: string) => [...memoKeys.all, "comments", name] as const,
}; };
export function useMemos(request: Partial<ListMemosRequest> = {}) { export function useMemos(request: Partial<ListMemosRequest> = {}) {
...@@ -139,3 +140,15 @@ export function useDeleteMemo() { ...@@ -139,3 +140,15 @@ export function useDeleteMemo() {
}, },
}); });
} }
export function useMemoComments(name: string, options?: { enabled?: boolean }) {
return useQuery({
queryKey: memoKeys.comments(name),
queryFn: async () => {
const response = await memoServiceClient.listMemoComments({ name });
return response;
},
enabled: options?.enabled ?? true,
staleTime: 1000 * 60, // 1 minute
});
}
...@@ -10,11 +10,10 @@ import MobileHeader from "@/components/MobileHeader"; ...@@ -10,11 +10,10 @@ import MobileHeader from "@/components/MobileHeader";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { memoNamePrefix } from "@/helpers/resource-names"; import { memoNamePrefix } from "@/helpers/resource-names";
import useCurrentUser from "@/hooks/useCurrentUser"; import useCurrentUser from "@/hooks/useCurrentUser";
import { useMemo as useMemoQuery } from "@/hooks/useMemoQueries"; import { useMemo, useMemoComments } from "@/hooks/useMemoQueries";
import useNavigateTo from "@/hooks/useNavigateTo"; import useNavigateTo from "@/hooks/useNavigateTo";
import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import useResponsiveWidth from "@/hooks/useResponsiveWidth";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Memo, MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb";
import { useTranslate } from "@/utils/i18n"; import { useTranslate } from "@/utils/i18n";
const MemoDetail = () => { const MemoDetail = () => {
...@@ -29,7 +28,7 @@ const MemoDetail = () => { ...@@ -29,7 +28,7 @@ const MemoDetail = () => {
const [showCommentEditor, setShowCommentEditor] = useState(false); const [showCommentEditor, setShowCommentEditor] = useState(false);
// Fetch main memo with React Query // Fetch main memo with React Query
const { data: memo, error, isLoading } = useMemoQuery(memoName, { enabled: !!memoName }); const { data: memo, error, isLoading } = useMemo(memoName, { enabled: !!memoName });
// Handle errors // Handle errors
if (error) { if (error) {
...@@ -38,18 +37,15 @@ const MemoDetail = () => { ...@@ -38,18 +37,15 @@ const MemoDetail = () => {
} }
// Fetch parent memo if exists // Fetch parent memo if exists
const { data: parentMemo } = useMemoQuery(memo?.parent || "", { const { data: parentMemo } = useMemo(memo?.parent || "", {
enabled: !!memo?.parent, enabled: !!memo?.parent,
}); });
// Get comment relations and memo names // Fetch all comments for this memo in a single query
const commentRelations = const { data: commentsResponse } = useMemoComments(memoName, {
memo?.relations.filter((relation) => relation.relatedMemo?.name === memo.name && relation.type === MemoRelation_Type.COMMENT) || []; enabled: !!memo,
const commentMemoNames = commentRelations.map((relation) => relation.memo!.name); });
const comments = commentsResponse?.memos || [];
// Fetch all comment memos
const commentQueries = commentMemoNames.map((name) => useMemoQuery(name));
const comments = commentQueries.map((q) => q.data).filter((memo): memo is Memo => !!memo);
const showCreateCommentButton = currentUser && !showCommentEditor; const showCreateCommentButton = currentUser && !showCommentEditor;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment