Skip to content

Commit e94f128

Browse files
feat: enhance list mutation handling with optimistic updates and snapshot restoration
1 parent 2cec9ea commit e94f128

1 file changed

Lines changed: 87 additions & 6 deletions

File tree

client/src/features/lists/hooks/useLists.ts

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ import {
66
} from '@/features/lists/services/listService';
77
import { getLocalStorageByRegex } from '@/features/lists/utils/getLocalStorageByRegex';
88
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
9+
import { ListProps } from '@shared/types/list.types';
10+
11+
const LISTS_QUERY_KEY = ['lists'] as const;
12+
13+
type ListsSnapshot = Array<[readonly unknown[], ListProps[] | undefined]>;
14+
15+
const restoreListsSnapshot = (
16+
queryClient: ReturnType<typeof useQueryClient>,
17+
snapshot: ListsSnapshot
18+
) => {
19+
snapshot.forEach(([queryKey, data]) => {
20+
queryClient.setQueryData(queryKey, data);
21+
});
22+
};
923

1024
export const useLists = () => {
1125
const authToken = getLocalStorageByRegex(/auth-token/i);
@@ -34,9 +48,29 @@ export const useCreateList = () => {
3448
const queryClient = useQueryClient();
3549
return useMutation({
3650
mutationFn: createList,
37-
onSuccess: () => {
51+
onMutate: async ({ body }) => {
52+
await queryClient.cancelQueries({
53+
queryKey: LISTS_QUERY_KEY,
54+
});
55+
56+
const previousLists = queryClient.getQueriesData<ListProps[]>({
57+
queryKey: LISTS_QUERY_KEY,
58+
});
59+
60+
queryClient.setQueriesData<ListProps[]>({ queryKey: LISTS_QUERY_KEY }, (old) => {
61+
const currentLists = old ?? [];
62+
return [...currentLists, body];
63+
});
64+
65+
return { previousLists };
66+
},
67+
onError: (_error, _variables, context) => {
68+
if (!context) return;
69+
restoreListsSnapshot(queryClient, context.previousLists);
70+
},
71+
onSettled: () => {
3872
queryClient.invalidateQueries({
39-
queryKey: ['lists'],
73+
queryKey: LISTS_QUERY_KEY,
4074
});
4175
},
4276
});
@@ -46,9 +80,36 @@ export const useUpdateList = () => {
4680
const queryClient = useQueryClient();
4781
return useMutation({
4882
mutationFn: updateList,
49-
onSuccess: () => {
83+
onMutate: async ({ listId, body }) => {
84+
await queryClient.cancelQueries({
85+
queryKey: LISTS_QUERY_KEY,
86+
});
87+
88+
const previousLists = queryClient.getQueriesData<ListProps[]>({
89+
queryKey: LISTS_QUERY_KEY,
90+
});
91+
92+
queryClient.setQueriesData<ListProps[]>({ queryKey: LISTS_QUERY_KEY }, (old) => {
93+
if (!old) return old;
94+
return old.map((list) =>
95+
list.listId === listId
96+
? {
97+
...list,
98+
...body,
99+
}
100+
: list
101+
);
102+
});
103+
104+
return { previousLists };
105+
},
106+
onError: (_error, _variables, context) => {
107+
if (!context) return;
108+
restoreListsSnapshot(queryClient, context.previousLists);
109+
},
110+
onSettled: () => {
50111
queryClient.invalidateQueries({
51-
queryKey: ['lists'],
112+
queryKey: LISTS_QUERY_KEY,
52113
});
53114
},
54115
});
@@ -58,9 +119,29 @@ export const useDeleteList = () => {
58119
const queryClient = useQueryClient();
59120
return useMutation({
60121
mutationFn: deleteList,
61-
onSuccess: () => {
122+
onMutate: async ({ listId }) => {
123+
await queryClient.cancelQueries({
124+
queryKey: LISTS_QUERY_KEY,
125+
});
126+
127+
const previousLists = queryClient.getQueriesData<ListProps[]>({
128+
queryKey: LISTS_QUERY_KEY,
129+
});
130+
131+
queryClient.setQueriesData<ListProps[]>({ queryKey: LISTS_QUERY_KEY }, (old) => {
132+
if (!old) return old;
133+
return old.filter((list) => list.listId !== listId);
134+
});
135+
136+
return { previousLists };
137+
},
138+
onError: (_error, _variables, context) => {
139+
if (!context) return;
140+
restoreListsSnapshot(queryClient, context.previousLists);
141+
},
142+
onSettled: () => {
62143
queryClient.invalidateQueries({
63-
queryKey: ['lists'],
144+
queryKey: LISTS_QUERY_KEY,
64145
});
65146
},
66147
});

0 commit comments

Comments
 (0)