From ee07fb2a3836d6298bdced88374bde266258eb42 Mon Sep 17 00:00:00 2001 From: Nathan Panchout Date: Tue, 3 Mar 2026 09:45:10 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20improve=20pagina?= =?UTF-8?q?tion=20UX=20and=20simplify=20mutation=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use placeholderData in useInfiniteChildren and useInfiniteItems to prevent layout flicker on re-fetch. Remove addItemToTop from useOptimisticPagination. Simplify useMutations by removing unused logic. --- .../explorer/hooks/useInfiniteChildren.ts | 1 + .../explorer/hooks/useInfiniteItems.ts | 1 + .../features/explorer/hooks/useMutations.ts | 19 ++--- .../explorer/hooks/useOptimisticPagination.ts | 81 ------------------- 4 files changed, 7 insertions(+), 95 deletions(-) diff --git a/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteChildren.ts b/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteChildren.ts index a701078f..e687dd6f 100644 --- a/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteChildren.ts +++ b/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteChildren.ts @@ -31,5 +31,6 @@ export const useInfiniteChildren = ( }, initialPageParam: 1, enabled: enabled && itemId !== null, + placeholderData: (previousData) => previousData, }); }; diff --git a/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteItems.ts b/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteItems.ts index 23ec0da4..eb9afa19 100644 --- a/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteItems.ts +++ b/src/frontend/apps/drive/src/features/explorer/hooks/useInfiniteItems.ts @@ -32,6 +32,7 @@ const createInfiniteItemsHook = ( }, initialPageParam: 1, enabled: enabled, + placeholderData: (previousData) => previousData, }); }; }; diff --git a/src/frontend/apps/drive/src/features/explorer/hooks/useMutations.ts b/src/frontend/apps/drive/src/features/explorer/hooks/useMutations.ts index 761b65c9..96739f69 100644 --- a/src/frontend/apps/drive/src/features/explorer/hooks/useMutations.ts +++ b/src/frontend/apps/drive/src/features/explorer/hooks/useMutations.ts @@ -5,10 +5,7 @@ import { useGlobalExplorer, generateTreeId, } from "../components/GlobalExplorerContext"; -import { - useAddItemToPaginatedList, - useRemoveItemsFromPaginatedList, -} from "./useOptimisticPagination"; +import { useRemoveItemsFromPaginatedList } from "./useOptimisticPagination"; import { useTreeContext } from "@gouvfr-lasuite/ui-kit"; import { useRefreshQueryCacheAfterMutation, @@ -122,17 +119,14 @@ export const useMutationRenameItem = () => { export const useMutationCreateFolder = () => { const driver = getDriver(); - const addItemToTopOfPaginatedList = useAddItemToPaginatedList(); + const refresh = useRefreshQueryCacheAfterMutation(); return useMutation({ mutationFn: (...payload: Parameters) => { return driver.createFolder(...payload); }, - onSuccess: (data, variables) => { - const queryKey = variables.parentId - ? ["items", variables.parentId, "children"] - : ["items", "infinite", JSON.stringify({ is_creator_me: true })]; - addItemToTopOfPaginatedList(queryKey, data); + onSuccess: (_, variables) => { + refresh(variables.parentId); }, }); }; @@ -258,10 +252,7 @@ export const useMutationDeleteFavoriteItem = () => { true, ); treeContext?.treeData.deleteNode(rootFavoriteTreeId); - removeItems( - ["items", "infinite", JSON.stringify({ is_favorite: true })], - [itemId], - ); + removeItems(["items", "infinite"], [itemId]); refreshItemCache(itemId, { is_favorite: false }); refreshFavoriteCache(itemId, false); }, diff --git a/src/frontend/apps/drive/src/features/explorer/hooks/useOptimisticPagination.ts b/src/frontend/apps/drive/src/features/explorer/hooks/useOptimisticPagination.ts index bfc7cd16..de5617f6 100644 --- a/src/frontend/apps/drive/src/features/explorer/hooks/useOptimisticPagination.ts +++ b/src/frontend/apps/drive/src/features/explorer/hooks/useOptimisticPagination.ts @@ -2,60 +2,6 @@ import { Item } from "@/features/drivers/types"; import { PaginatedChildrenResult } from "@gouvfr-lasuite/ui-kit"; import { QueryClient, QueryKey, useQueryClient } from "@tanstack/react-query"; -/** - * Adds an item to the top of the first page of a paginated infinite query list. - * This function finds all queries matching the queryKey pattern and updates them - * by prepending the new item to the first page. - * - * @param queryClient - The react-query QueryClient instance - * @param queryKey - The query key pattern to match (can be partial) - * @param newItem - The item to add at the top of the list - */ -export const addItemToTopOfPaginatedList = ( - queryClient: QueryClient, - queryKey: QueryKey, - newItem: Item -): void => { - // Get all queries matching the queryKey pattern - const queriesData = queryClient.getQueriesData({ - queryKey, - }); - - queriesData.forEach((query) => { - const key = query[0]; - const data = query[1] as - | { pages: PaginatedChildrenResult[] } - | undefined; - - if (!data || !data.pages || data.pages.length === 0) { - return; - } - - // Deep clone to avoid mutating the original data - const updatedData: { pages: PaginatedChildrenResult[] } = JSON.parse( - JSON.stringify(data) - ); - - // Add the new item to the top of the first page - if (updatedData.pages[0]) { - // Check if item already exists to avoid duplicates - const itemExists = updatedData.pages.some((page) => - page.children?.some((child) => child.id === newItem.id) - ); - - if (!itemExists) { - updatedData.pages[0].children = [ - newItem, - ...(updatedData.pages[0].children || []), - ]; - } - } - - // Update the query data - queryClient.setQueryData(key, updatedData); - }); -}; - /** * Removes items from a paginated infinite query list. * This function finds all queries matching the queryKey pattern and updates them @@ -102,33 +48,6 @@ export const removeItemsFromPaginatedList = ( }); }; -/** - * Hook that returns a function to add an item to the top of a paginated list. - * This is a convenience hook that provides access to the queryClient. - * - * @example - * ```tsx - * const addItemToTop = useAddItemToPaginatedList(); - * - * // In a mutation's onSuccess callback: - * onSuccess: (newItem) => { - * addItemToTop( - * ["items", parentId, "children", "infinite"], - * newItem - * ); - * } - * ``` - * - * @returns A function that takes a queryKey and an item, and adds the item to the top of the list - */ -export const useAddItemToPaginatedList = () => { - const queryClient = useQueryClient(); - - return (queryKey: QueryKey, newItem: Item) => { - addItemToTopOfPaginatedList(queryClient, queryKey, newItem); - }; -}; - /** * Hook that returns a function to remove items from a paginated list. * This is a convenience hook that provides access to the queryClient.