Skip to content

Commit 12f822f

Browse files
authored
Merge pull request #11016 from marmelab/revert-11013-fix-optimistic-query-invalidation
Revert "Fix optimistic query invalidation"
2 parents e07cbb5 + 3dda9df commit 12f822f

17 files changed

+132
-617
lines changed

packages/ra-core/src/dataProvider/useCreate.spec.tsx

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,7 @@ import {
2626
WithMiddlewaresSuccess as WithMiddlewaresSuccessUndoable,
2727
WithMiddlewaresError as WithMiddlewaresErrorUndoable,
2828
} from './useCreate.undoable.stories';
29-
import {
30-
Middleware,
31-
MutationMode,
32-
Params,
33-
InvalidateList,
34-
} from './useCreate.stories';
29+
import { Middleware, MutationMode, Params } from './useCreate.stories';
3530

3631
describe('useCreate', () => {
3732
it('returns a callback that can be used with create arguments', async () => {
@@ -632,15 +627,4 @@ describe('useCreate', () => {
632627
await screen.findByText('Bazinga');
633628
});
634629
});
635-
636-
it('invalidates getList query when dataProvider resolves in undoable mode', async () => {
637-
render(<InvalidateList mutationMode="undoable" />);
638-
fireEvent.change(await screen.findByLabelText('title'), {
639-
target: { value: 'New Post' },
640-
});
641-
fireEvent.click(screen.getByText('Save'));
642-
await screen.findByText('resources.posts.notifications.created');
643-
fireEvent.click(screen.getByText('Close'));
644-
await screen.findByText('3: New Post');
645-
});
646630
});

packages/ra-core/src/dataProvider/useCreate.stories.tsx

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as React from 'react';
22
import { QueryClient, useIsMutating } from '@tanstack/react-query';
3-
import fakeRestDataProvider from 'ra-data-fakerest';
43

54
import { CoreAdmin, CoreAdminContext, Resource } from '../core';
65
import { useCreate } from './useCreate';
@@ -384,70 +383,3 @@ const RefreshButton = () => {
384383
</button>
385384
);
386385
};
387-
388-
export const InvalidateList = ({
389-
mutationMode,
390-
}: {
391-
mutationMode: MutationModeType;
392-
}) => {
393-
const dataProvider = fakeRestDataProvider(
394-
{
395-
posts: [
396-
{ id: 1, title: 'Hello' },
397-
{ id: 2, title: 'World' },
398-
],
399-
},
400-
process.env.NODE_ENV !== 'test',
401-
process.env.NODE_ENV === 'test' ? 10 : 1000
402-
);
403-
404-
return (
405-
<TestMemoryRouter initialEntries={['/posts/create']}>
406-
<CoreAdmin dataProvider={dataProvider}>
407-
<Resource
408-
name="posts"
409-
create={
410-
<CreateBase mutationMode={mutationMode}>
411-
<Form>
412-
{mutationMode !== 'pessimistic' && (
413-
<TextInput source="id" defaultValue={3} />
414-
)}
415-
<TextInput source="title" />
416-
<button type="submit">Save</button>
417-
</Form>
418-
</CreateBase>
419-
}
420-
list={
421-
<ListBase loading={<p>Loading...</p>}>
422-
<RecordsIterator
423-
render={(record: any) => (
424-
<div
425-
style={{
426-
display: 'flex',
427-
gap: '8px',
428-
alignItems: 'center',
429-
}}
430-
>
431-
{record.id}: {record.title}
432-
</div>
433-
)}
434-
/>
435-
<Notification />
436-
</ListBase>
437-
}
438-
/>
439-
</CoreAdmin>
440-
</TestMemoryRouter>
441-
);
442-
};
443-
InvalidateList.args = {
444-
mutationMode: 'undoable',
445-
};
446-
InvalidateList.argTypes = {
447-
mutationMode: {
448-
control: {
449-
type: 'select',
450-
},
451-
options: ['pessimistic', 'optimistic', 'undoable'],
452-
},
453-
};

packages/ra-core/src/dataProvider/useCreate.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export const useCreate = <
160160

161161
return clonedData;
162162
},
163-
getQueryKeys: ({ resource, ...params }, { mutationMode }) => {
163+
getSnapshot: ({ resource, ...params }, { mutationMode }) => {
164164
const queryKeys: any[] = [
165165
[resource, 'getList'],
166166
[resource, 'getInfiniteList'],
@@ -176,7 +176,27 @@ export const useCreate = <
176176
]);
177177
}
178178

179-
return queryKeys;
179+
/**
180+
* Snapshot the previous values via queryClient.getQueriesData()
181+
*
182+
* The snapshotData ref will contain an array of tuples [query key, associated data]
183+
*
184+
* @example
185+
* [
186+
* [['posts', 'getOne', { id: '1' }], { id: 1, title: 'Hello' }],
187+
* [['posts', 'getList'], { data: [{ id: 1, title: 'Hello' }], total: 1 }],
188+
* [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
189+
* ]
190+
*
191+
* @see https://react-query-v3.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
192+
*/
193+
const snapshot = queryKeys.reduce(
194+
(prev, queryKey) =>
195+
prev.concat(queryClient.getQueriesData({ queryKey })),
196+
[] as Snapshot
197+
);
198+
199+
return snapshot;
180200
},
181201
getMutateWithMiddlewares: mutationFn => {
182202
if (getMutateWithMiddlewares) {

packages/ra-core/src/dataProvider/useDelete.spec.tsx

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
ErrorCase as ErrorCaseUndoable,
2121
SuccessCase as SuccessCaseUndoable,
2222
} from './useDelete.undoable.stories';
23-
import { MutationMode, Params, InvalidateList } from './useDelete.stories';
23+
import { MutationMode, Params } from './useDelete.stories';
2424

2525
describe('useDelete', () => {
2626
it('returns a callback that can be used with deleteOne arguments', async () => {
@@ -732,16 +732,5 @@ describe('useDelete', () => {
732732
});
733733
});
734734
});
735-
736-
it('invalidates getList query when dataProvider resolves in undoable mode', async () => {
737-
render(<InvalidateList mutationMode="undoable" />);
738-
await screen.findByText('Title: Hello');
739-
fireEvent.click(await screen.findByText('Delete'));
740-
await screen.findByText('resources.posts.notifications.deleted');
741-
fireEvent.click(screen.getByText('Close'));
742-
await waitFor(() => {
743-
expect(screen.queryByText('1: Hello')).toBeNull();
744-
});
745-
});
746735
});
747736
});

packages/ra-core/src/dataProvider/useDelete.stories.tsx

Lines changed: 1 addition & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
import * as React from 'react';
22
import { useState } from 'react';
33
import { QueryClient, useIsMutating } from '@tanstack/react-query';
4-
import fakeRestDataProvider from 'ra-data-fakerest';
54

6-
import { CoreAdmin, CoreAdminContext, Resource } from '../core';
5+
import { CoreAdminContext } from '../core';
76
import { useDelete } from './useDelete';
87
import { useGetList } from './useGetList';
98
import type { DataProvider, MutationMode as MutationModeType } from '../types';
10-
import {
11-
EditBase,
12-
ListBase,
13-
RecordsIterator,
14-
useDeleteController,
15-
WithRecord,
16-
} from '../controller';
17-
import { TestMemoryRouter } from '../routing';
18-
import { useNotificationContext } from '../notification';
19-
import { useTakeUndoableMutation } from './undo';
209

2110
export default { title: 'ra-core/dataProvider/useDelete' };
2211

@@ -173,110 +162,3 @@ const ParamsCore = () => {
173162
</>
174163
);
175164
};
176-
177-
const Notification = () => {
178-
const { notifications, resetNotifications } = useNotificationContext();
179-
const takeMutation = useTakeUndoableMutation();
180-
181-
return notifications.length > 0 ? (
182-
<>
183-
<div>{notifications[0].message}</div>
184-
<div style={{ display: 'flex', gap: '16px' }}>
185-
<button
186-
onClick={() => {
187-
if (notifications[0].notificationOptions?.undoable) {
188-
const mutation = takeMutation();
189-
if (mutation) {
190-
mutation({ isUndo: false });
191-
}
192-
}
193-
resetNotifications();
194-
}}
195-
>
196-
Close
197-
</button>
198-
</div>
199-
</>
200-
) : null;
201-
};
202-
203-
const DeleteButton = ({ mutationMode }: { mutationMode: MutationModeType }) => {
204-
const { isPending, handleDelete } = useDeleteController({
205-
mutationMode,
206-
redirect: 'list',
207-
});
208-
return (
209-
<button onClick={handleDelete} disabled={isPending}>
210-
Delete
211-
</button>
212-
);
213-
};
214-
215-
export const InvalidateList = ({
216-
mutationMode,
217-
}: {
218-
mutationMode: MutationModeType;
219-
}) => {
220-
const dataProvider = fakeRestDataProvider(
221-
{
222-
posts: [
223-
{ id: 1, title: 'Hello' },
224-
{ id: 2, title: 'World' },
225-
],
226-
},
227-
process.env.NODE_ENV !== 'test',
228-
process.env.NODE_ENV === 'test' ? 10 : 1000
229-
);
230-
231-
return (
232-
<TestMemoryRouter initialEntries={['/posts/1']}>
233-
<CoreAdmin dataProvider={dataProvider}>
234-
<Resource
235-
name="posts"
236-
edit={
237-
<EditBase>
238-
<div>
239-
<h1>Edit Post</h1>
240-
<WithRecord
241-
render={record => (
242-
<div>Title: {record.title}</div>
243-
)}
244-
/>
245-
<DeleteButton mutationMode={mutationMode} />
246-
</div>
247-
</EditBase>
248-
}
249-
list={
250-
<ListBase loading={<p>Loading...</p>}>
251-
<RecordsIterator
252-
render={(record: any) => (
253-
<div
254-
style={{
255-
display: 'flex',
256-
gap: '8px',
257-
alignItems: 'center',
258-
}}
259-
>
260-
{record.id}: {record.title}
261-
</div>
262-
)}
263-
/>
264-
<Notification />
265-
</ListBase>
266-
}
267-
/>
268-
</CoreAdmin>
269-
</TestMemoryRouter>
270-
);
271-
};
272-
InvalidateList.args = {
273-
mutationMode: 'undoable',
274-
};
275-
InvalidateList.argTypes = {
276-
mutationMode: {
277-
control: {
278-
type: 'select',
279-
},
280-
options: ['pessimistic', 'optimistic', 'undoable'],
281-
},
282-
};

packages/ra-core/src/dataProvider/useDelete.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,34 @@ export const useDelete = <
211211

212212
return params.previousData;
213213
},
214-
getQueryKeys: ({ resource }) => {
214+
getSnapshot: ({ resource }) => {
215215
const queryKeys = [
216216
[resource, 'getList'],
217217
[resource, 'getInfiniteList'],
218218
[resource, 'getMany'],
219219
[resource, 'getManyReference'],
220220
];
221-
return queryKeys;
221+
222+
/**
223+
* Snapshot the previous values via queryClient.getQueriesData()
224+
*
225+
* The snapshotData ref will contain an array of tuples [query key, associated data]
226+
*
227+
* @example
228+
* [
229+
* [['posts', 'getList'], { data: [{ id: 1, title: 'Hello' }], total: 1 }],
230+
* [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
231+
* ]
232+
*
233+
* @see https://tanstack.com/query/v5/docs/react/reference/QueryClient#queryclientgetqueriesdata
234+
*/
235+
const snapshot = queryKeys.reduce(
236+
(prev, queryKey) =>
237+
prev.concat(queryClient.getQueriesData({ queryKey })),
238+
[] as Snapshot
239+
);
240+
241+
return snapshot;
222242
},
223243
onSettled: (
224244
result,

packages/ra-core/src/dataProvider/useDeleteMany.spec.tsx

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { QueryClient, useMutationState } from '@tanstack/react-query';
66
import { CoreAdminContext } from '../core';
77
import { testDataProvider } from './testDataProvider';
88
import { useDeleteMany } from './useDeleteMany';
9-
import { MutationMode, Params, InvalidateList } from './useDeleteMany.stories';
9+
import { MutationMode, Params } from './useDeleteMany.stories';
1010

1111
describe('useDeleteMany', () => {
1212
it('returns a callback that can be used with update arguments', async () => {
@@ -390,15 +390,5 @@ describe('useDeleteMany', () => {
390390
});
391391
});
392392
});
393-
394-
it('invalidates getList query when dataProvider resolves in undoable mode', async () => {
395-
render(<InvalidateList mutationMode="undoable" />);
396-
fireEvent.click(await screen.findByText('Delete'));
397-
await screen.findByText('resources.posts.notifications.deleted');
398-
fireEvent.click(screen.getByText('Close'));
399-
await waitFor(() => {
400-
expect(screen.queryByText('1: Hello')).toBeNull();
401-
});
402-
});
403393
});
404394
});

0 commit comments

Comments
 (0)