mirror of
https://github.com/suitenumerique/drive.git
synced 2026-09-28 04:25:13 +02:00
♻️(frontend) improve pagination UX and simplify mutation hooks
Use placeholderData in useInfiniteChildren and useInfiniteItems to prevent layout flicker on re-fetch. Remove addItemToTop from useOptimisticPagination. Simplify useMutations by removing unused logic.
This commit is contained in:
@@ -31,5 +31,6 @@ export const useInfiniteChildren = (
|
||||
},
|
||||
initialPageParam: 1,
|
||||
enabled: enabled && itemId !== null,
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ const createInfiniteItemsHook = (
|
||||
},
|
||||
initialPageParam: 1,
|
||||
enabled: enabled,
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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<typeof driver.createFolder>) => {
|
||||
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);
|
||||
},
|
||||
|
||||
@@ -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<Item>[] }
|
||||
| undefined;
|
||||
|
||||
if (!data || !data.pages || data.pages.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Deep clone to avoid mutating the original data
|
||||
const updatedData: { pages: PaginatedChildrenResult<Item>[] } = 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.
|
||||
|
||||
Reference in New Issue
Block a user