Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade react-query to v5, react 18 and yarn v4 #9473

Merged
merged 103 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
dc19387
Upgrade react-query to v5
djhi Nov 21, 2023
825af95
Upgrade dependencies
djhi Nov 21, 2023
fa12ff8
Update ra-ui-materialui
djhi Nov 21, 2023
a320921
Update ra-no-code
djhi Nov 21, 2023
c1a8e65
Upgrade testing-library
djhi Nov 21, 2023
3a60f8c
Update examples
djhi Nov 21, 2023
6059cd8
Update react-test-renderer
djhi Nov 21, 2023
5c49394
Fix useGetOne and useShowController
djhi Nov 21, 2023
929620d
Fix some auth tests
djhi Nov 21, 2023
14e3c50
Fix useAuthState
djhi Nov 21, 2023
c093b90
Fix useListController
djhi Nov 21, 2023
b06d9ea
Fix react-query imports
djhi Nov 21, 2023
ae03d12
Fix useUnique tests
djhi Nov 21, 2023
228c424
Fix useConfigureAdminRouterFromChildren tests
djhi Nov 21, 2023
12b4fb1
Fix useGetList
djhi Nov 22, 2023
399b851
Fix useGetOne
djhi Nov 22, 2023
af0d038
Fix useInfiniteGetList
djhi Nov 22, 2023
984ed31
Fix useGetMany
djhi Nov 22, 2023
a2207c4
Fix CoreAdminRoutes
djhi Nov 22, 2023
ab9bbe0
Fix useCreatePath
djhi Nov 22, 2023
ae4388f
Fix Resource
djhi Nov 22, 2023
2bb0ad9
Fix useHandleAuthCallback
djhi Nov 22, 2023
feeea9c
Fix useAuthenticated
djhi Nov 22, 2023
2e890cd
Fix Authenticated
djhi Nov 22, 2023
f65459e
Fix useUpdate
djhi Nov 22, 2023
958811f
Fix useDelete
djhi Nov 22, 2023
5966771
Fix useListController
djhi Nov 22, 2023
7455168
Fix useInfiniteListController
djhi Nov 22, 2023
e33f02b
Fix ReferenceManyField
djhi Nov 22, 2023
37c4578
Fix some ra-ui-materialui tests
djhi Nov 22, 2023
76f3b39
Upgrade MUI
djhi Nov 23, 2023
34359e8
Fix remaining tests
djhi Nov 23, 2023
8d3703c
Fix build
djhi Nov 23, 2023
782c7c9
Fix data and error checks
djhi Nov 23, 2023
ce8fe48
Fix side effects
djhi Nov 23, 2023
927711f
Fix e2e tests
djhi Nov 23, 2023
3b569f0
Fix side effects management in useEditController
djhi Nov 23, 2023
d33e455
Fix lint error
djhi Nov 23, 2023
011ca15
Fix unstable test
djhi Nov 23, 2023
5271d97
Stabilize more tests
djhi Nov 23, 2023
eb91d20
Cleanup some test logs
djhi Nov 23, 2023
00f25a5
Add upgrade guide
djhi Nov 24, 2023
0eae7ec
Explain side effects handling in useEditController
djhi Nov 24, 2023
e1e9db4
Fix form props
djhi Nov 24, 2023
fe3d1df
Fix simple example
djhi Nov 24, 2023
da68f59
Fix simple example build for e2e
djhi Nov 24, 2023
bea5ff1
Upgrade to yarn v4
djhi Nov 24, 2023
fd7d671
Use node 18 in GH Actions
djhi Nov 24, 2023
cd30bb4
Disable HardenedMode
djhi Nov 24, 2023
415653c
Remove unnecessary comment
djhi Nov 27, 2023
f0c0f7f
Revert unnecessary breaking changes
djhi Nov 27, 2023
8230afc
Fix auth hooks and components
djhi Nov 27, 2023
63fd8c1
Simplify useHandleAuthCallback tests
djhi Nov 27, 2023
a72e735
Simplify simple example layout
djhi Nov 27, 2023
d3dfe38
Avoid authProvider changes
djhi Nov 27, 2023
fc9e231
Wrap user onSuccess and onError in useEvent
djhi Nov 27, 2023
2f48b32
Fix tests
djhi Nov 27, 2023
0a05e10
Move side effect handling to useUpdate
djhi Nov 27, 2023
525335b
Cleanup useUpdate
djhi Nov 28, 2023
7795bc9
Handle side effects in useUpdateMany
djhi Nov 28, 2023
c7d016d
Handle side effects in useDeleteMany & useDelete
djhi Nov 28, 2023
fa6afbc
Stabilize tests
djhi Nov 28, 2023
91c3064
Handle side effects in useCreate
djhi Nov 28, 2023
725fc5e
Move side effects at declaration time on useCreateController
djhi Nov 28, 2023
57ec1f9
Cleanup useInfiniteListController
djhi Nov 28, 2023
037c745
Format
djhi Nov 28, 2023
bed0034
Apply review suggestions
djhi Nov 28, 2023
f04c1f5
Fix side effects are executed twice on update
djhi Nov 28, 2023
db13b91
More upgrade instructions
fzaninotto Nov 29, 2023
0c04fff
[no ci] Fix incorrect upgrade instructions
fzaninotto Nov 29, 2023
66c4a98
Compactify
fzaninotto Nov 29, 2023
f3de1bc
Revert authentication related hooks changes
djhi Nov 29, 2023
f67760e
Use IsPending
djhi Nov 29, 2023
2ba92ba
Fix useReference tests
djhi Nov 29, 2023
1b69309
Fix Form Types
djhi Dec 4, 2023
0c3d7ab
Fix usePrevNextController
djhi Dec 4, 2023
13223b6
Fix useGetIdentity
djhi Dec 4, 2023
580446c
Fix more tests
djhi Dec 4, 2023
884a6f6
Fix useReferenceInputController
djhi Dec 4, 2023
883fbd3
Add more timeout on AutocompleteInput test
djhi Dec 4, 2023
158ce05
Simplify upgrade guide [skip-ci]
djhi Dec 4, 2023
713dfe2
Apply review suggestions
djhi Dec 6, 2023
a095293
Add onSettled support
djhi Dec 6, 2023
3fdbf51
Return null in useHandleAuthCallback
djhi Dec 6, 2023
6de1ab0
Apply review suggestions
djhi Dec 8, 2023
b89d378
Revert change on useAuthState to avoid BC
djhi Dec 8, 2023
fd48c78
Apply review suggestions
djhi Dec 8, 2023
f44a4c8
Fix eslint
djhi Dec 8, 2023
54c7eb7
Fix usePermissions
djhi Dec 8, 2023
26a0357
Fix useGetIdentity
djhi Dec 8, 2023
8a3aad6
Revert unnecessary changes
djhi Dec 8, 2023
9d3ca2b
Test false value in useAuthState
djhi Dec 8, 2023
b05bb58
Fix broken story
fzaninotto Dec 8, 2023
d804c14
Fix crm app
fzaninotto Dec 8, 2023
6d43aa2
Fix tutorial
fzaninotto Dec 8, 2023
49170f5
Fix ra-no-code
fzaninotto Dec 8, 2023
3dbffcf
Revert mui dep change
djhi Dec 8, 2023
317bd17
Apply review suggestions
djhi Dec 11, 2023
20b7931
Revert test change
djhi Dec 11, 2023
1fadea7
Don't trigger side effects while fetching
djhi Dec 11, 2023
85a21f4
Don't trigger side effects while fetching in auth hooks
djhi Dec 11, 2023
5300d06
Fix react query doc links
djhi Dec 13, 2023
a24aa9e
Apply suggestions from code review
djhi Dec 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/ra-core/src/auth/useGetIdentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export type UseGetIdentityResult<ErrorType = Error> = QueryObserverResult<
UserIdentity,
ErrorType
> & {
identity: UserIdentity;
identity: UserIdentity | null;
};

export default useGetIdentity;
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/auth/usePermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export type UsePermissionsResult<
PermissionsType = any,
ErrorType = Error
> = QueryObserverResult<PermissionsType, ErrorType> & {
permissions: PermissionsType;
permissions: PermissionsType | null;
};

const noop = () => {};
23 changes: 15 additions & 8 deletions packages/ra-core/src/controller/edit/useEditController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,11 @@ import {
* return <EditView {...controllerProps} {...props} />;
* }
*/
export const useEditController = <RecordType extends RaRecord = any>(
props: EditControllerProps<RecordType> = {}
export const useEditController = <
RecordType extends RaRecord = any,
ErrorType = Error
>(
props: EditControllerProps<RecordType, ErrorType> = {}
): EditControllerResult<RecordType> => {
const {
disableAuthentication,
Expand Down Expand Up @@ -127,7 +130,7 @@ export const useEditController = <RecordType extends RaRecord = any>(

const recordCached = { id, previousData: record };

const [update, { isPending: saving }] = useUpdate<RecordType>(
const [update, { isPending: saving }] = useUpdate<RecordType, ErrorType>(
resource,
recordCached,
{
Expand All @@ -149,15 +152,16 @@ export const useEditController = <RecordType extends RaRecord = any>(
notify(
typeof error === 'string'
? error
: error.message || 'ra.notification.http_error',
: (error as Error).message ||
'ra.notification.http_error',
{
type: 'error',
messageArgs: {
_:
typeof error === 'string'
? error
: error && error.message
? error.message
: error && (error as Error).message
? (error as Error).message
: undefined,
},
}
Expand Down Expand Up @@ -240,11 +244,14 @@ export const useEditController = <RecordType extends RaRecord = any>(
};
};

export interface EditControllerProps<RecordType extends RaRecord = any> {
export interface EditControllerProps<
RecordType extends RaRecord = any,
ErrorType = Error
> {
disableAuthentication?: boolean;
id?: RecordType['id'];
mutationMode?: MutationMode;
mutationOptions?: UseUpdateOptions<RecordType>;
mutationOptions?: UseUpdateOptions<RecordType, ErrorType>;
queryOptions?: UseGetOneOptions<RecordType>;
redirect?: RedirectionSideEffect;
resource?: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/ra-core/src/dataProvider/useCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { useEvent } from '../util';
* This hook uses react-query useMutation under the hood.
* This means the state object contains mutate, isIdle, reset and other react-query methods.
*
* @see https://react-query-v3.tanstack.com/reference/useMutation
* @see https://react-query-v5.tanstack.com/reference/useMutation
slax57 marked this conversation as resolved.
Show resolved Hide resolved
*
* @example // set params when calling the create callback
*
Expand Down
6 changes: 3 additions & 3 deletions packages/ra-core/src/dataProvider/useDelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { useEvent } from '../util';
* This hook uses react-query useMutation under the hood.
* This means the state object contains mutate, isIdle, reset and other react-query methods.
*
* @see https://react-query-v3.tanstack.com/reference/useMutation
* @see https://react-query-v5.tanstack.com/reference/useMutation
*
* @example // set params when calling the deleteOne callback
*
Expand Down Expand Up @@ -325,7 +325,7 @@ export const useDelete = <
previousData: callTimePreviousData = previousData,
} = callTimeParams;

// optimistic update as documented in https://react-query-v3.tanstack.com/guides/optimistic-updates
// optimistic update as documented in https://react-query-v5.tanstack.com/guides/optimistic-updates
// except we do it in a mutate wrapper instead of the onMutate callback
// to have access to success side effects

Expand All @@ -347,7 +347,7 @@ export const useDelete = <
* [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
* ]
*
* @see https://react-query-v3.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
* @see https://react-query-v5.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
*/
snapshot.current = queryKeys.reduce(
(prev, queryKey) =>
Expand Down
6 changes: 3 additions & 3 deletions packages/ra-core/src/dataProvider/useDeleteMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { useEvent } from '../util';
* This hook uses react-query useMutation under the hood.
* This means the state object contains mutate, isIdle, reset and other react-query methods.
*
* @see https://react-query-v3.tanstack.com/reference/useMutation
* @see https://react-query-v5.tanstack.com/reference/useMutation
*
* @example // set params when calling the deleteMany callback
*
Expand Down Expand Up @@ -337,7 +337,7 @@ export const useDeleteMany = <

const { ids: callTimeIds = ids } = callTimeParams;

// optimistic update as documented in https://react-query-v3.tanstack.com/guides/optimistic-updates
// optimistic update as documented in https://react-query-v5.tanstack.com/guides/optimistic-updates
// except we do it in a mutate wrapper instead of the onMutate callback
// to have access to success side effects

Expand All @@ -359,7 +359,7 @@ export const useDeleteMany = <
* [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
* ]
*
* @see https://react-query-v3.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
* @see https://react-query-v5.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
*/
snapshot.current = queryKeys.reduce(
(prev, queryKey) =>
Expand Down
36 changes: 0 additions & 36 deletions packages/ra-core/src/dataProvider/useGetList.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -404,40 +404,4 @@ describe('useGetList', () => {
queryClient.getQueryData(['posts', 'getOne', { id: '1' }])
).toBeUndefined();
});

// NOTE: it seems that disabled queries are not updated anymore when the cache is updated
it.skip('should not fail when the query is disabled and the cache gets updated by another query', async () => {
const callback: any = jest.fn();
const onSuccess = jest.fn();
const queryClient = new QueryClient();
const dataProvider = testDataProvider({
// @ts-ignore
getList: jest.fn(() =>
Promise.resolve({ data: [{ id: 1, title: 'live' }], total: 1 })
),
});
render(
<CoreAdminContext
queryClient={queryClient}
dataProvider={dataProvider}
>
<UseGetList
options={{ enabled: false, onSuccess }}
callback={callback}
/>
</CoreAdminContext>
);
await waitFor(() => {
expect(callback).toHaveBeenCalled();
});
// Simulate the side-effect of e.g. a call to delete
queryClient.setQueriesData(
{ queryKey: ['posts', 'getList'] },
res => res
);
// If we get this far without an error being thrown, the test passes
await waitFor(() => {
expect(onSuccess).toHaveBeenCalled();
});
});
});
21 changes: 18 additions & 3 deletions packages/ra-core/src/dataProvider/useGetList.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react';
import { useEffect, useMemo, useRef } from 'react';
import {
useQuery,
UseQueryOptions,
Expand Down Expand Up @@ -99,6 +99,17 @@ export const useGetList = <RecordType extends RaRecord = any>(
...queryOptions,
});

const metaValue = useRef(meta);
const resourceValue = useRef(resource);

useEffect(() => {
metaValue.current = meta;
}, [meta]);

useEffect(() => {
resourceValue.current = resource;
}, [resource]);

useEffect(() => {
if (result.data === undefined) return;

Expand All @@ -109,13 +120,17 @@ export const useGetList = <RecordType extends RaRecord = any>(
) {
result.data.data.forEach(record => {
queryClient.setQueryData(
[resource, 'getOne', { id: String(record.id), meta }],
[
resourceValue.current,
'getOne',
{ id: String(record.id), meta: metaValue.current },
],
oldRecord => oldRecord ?? record
);
});
}
onSuccessEvent(result.data);
}, [meta, onSuccessEvent, queryClient, resource, result.data]);
}, [onSuccessEvent, queryClient, result.data]);

useEffect(() => {
if (result.error == null) return;
Expand Down
23 changes: 19 additions & 4 deletions packages/ra-core/src/dataProvider/useInfiniteGetList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import {

import { RaRecord, GetListParams, GetInfiniteListResult } from '../types';
import { useDataProvider } from './useDataProvider';
import { useEffect } from 'react';
import { useEffect, useRef } from 'react';
import { useEvent } from '../util';

/**
* Call the dataProvider.getList() method and return the resolved result
* as well as the loading state. The return from useInfiniteGetList is equivalent to the return from react-hook form useInfiniteQuery.
*
* @see https://react-query-v3.tanstack.com/reference/useInfiniteQuery
* @see https://react-query-v5.tanstack.com/reference/useInfiniteQuery
*
* This hook will return the cached result when called a second time
* with the same parameters, until the response arrives.
Expand Down Expand Up @@ -145,20 +145,35 @@ export const useInfiniteGetList = <RecordType extends RaRecord = any>(
},
});

const metaValue = useRef(meta);
const resourceValue = useRef(resource);

useEffect(() => {
metaValue.current = meta;
}, [meta]);

useEffect(() => {
resourceValue.current = resource;
}, [resource]);

useEffect(() => {
if (result.data === undefined) return;
// optimistically populate the getOne cache
result.data.pages.forEach(page => {
page.data.forEach(record => {
queryClient.setQueryData(
[resource, 'getOne', { id: String(record.id), meta }],
[
resourceValue.current,
'getOne',
{ id: String(record.id), meta: metaValue.current },
],
oldRecord => oldRecord ?? record
);
});
});

onSuccessEvent(result.data);
}, [meta, onSuccessEvent, queryClient, resource, result.data]);
}, [onSuccessEvent, queryClient, result.data]);

useEffect(() => {
if (result.error == null) return;
Expand Down
27 changes: 15 additions & 12 deletions packages/ra-core/src/dataProvider/useUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ import { useEvent } from '../util';
* const [update, { data }] = useUpdate<Product>('products', { id, data: diff, previousData: product });
* \-- data is Product
*/
export const useUpdate = <RecordType extends RaRecord = any>(
export const useUpdate = <RecordType extends RaRecord = any, ErrorType = Error>(
resource?: string,
params: Partial<UpdateParams<RecordType>> = {},
options: UseUpdateOptions<RecordType> = {}
): UseUpdateResult<RecordType, boolean> => {
options: UseUpdateOptions<RecordType, ErrorType> = {}
): UseUpdateResult<RecordType, boolean, ErrorType> => {
const dataProvider = useDataProvider();
const queryClient = useQueryClient();
const { id, data, meta } = params;
Expand Down Expand Up @@ -172,7 +172,7 @@ export const useUpdate = <RecordType extends RaRecord = any>(

const mutation = useMutation<
RecordType,
Error,
ErrorType,
Partial<UseUpdateMutateParams<RecordType>>
>({
mutationFn: ({
Expand Down Expand Up @@ -274,7 +274,7 @@ export const useUpdate = <RecordType extends RaRecord = any>(
callTimeParams: Partial<UpdateParams<RecordType>> = {},
callTimeOptions: MutateOptions<
RecordType,
unknown,
ErrorType,
Partial<UseUpdateMutateParams<RecordType>>,
unknown
> & { mutationMode?: MutationMode; returnPromise?: boolean } = {}
Expand Down Expand Up @@ -455,35 +455,38 @@ export interface UseUpdateMutateParams<RecordType extends RaRecord = any> {
}

export type UseUpdateOptions<
RecordType extends RaRecord = any
RecordType extends RaRecord = any,
ErrorType = Error
> = UseMutationOptions<
RecordType,
Error,
ErrorType,
Partial<Omit<UseUpdateMutateParams<RecordType>, 'mutationFn'>>
> & { mutationMode?: MutationMode; returnPromise?: boolean };

export type UpdateMutationFunction<
RecordType extends RaRecord = any,
TReturnPromise extends boolean = boolean
TReturnPromise extends boolean = boolean,
ErrorType = Error
> = (
resource?: string,
params?: Partial<UpdateParams<RecordType>>,
options?: MutateOptions<
RecordType,
Error,
ErrorType,
Partial<UseUpdateMutateParams<RecordType>>,
unknown
> & { mutationMode?: MutationMode; returnPromise?: TReturnPromise }
) => Promise<TReturnPromise extends true ? RecordType : void>;

export type UseUpdateResult<
RecordType extends RaRecord = any,
TReturnPromise extends boolean = boolean
TReturnPromise extends boolean = boolean,
ErrorType = Error
> = [
UpdateMutationFunction<RecordType, TReturnPromise>,
UpdateMutationFunction<RecordType, TReturnPromise, ErrorType>,
UseMutationResult<
RecordType,
Error,
ErrorType,
Partial<UpdateParams<RecordType> & { resource?: string }>,
unknown
>
Expand Down
6 changes: 3 additions & 3 deletions packages/ra-core/src/dataProvider/useUpdateMany.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import { Identifier } from '..';
* This hook uses react-query useMutation under the hood.
* This means the state object contains mutate, isIdle, reset and other react-query methods.
*
* @see https://react-query-v3.tanstack.com/reference/useMutation
* @see https://react-query-v5.tanstack.com/reference/useMutation
*
* @example // set params when calling the updateMany callback
*
Expand Down Expand Up @@ -341,7 +341,7 @@ export const useUpdateMany = <
meta: callTimeMeta = meta,
} = callTimeParams;

// optimistic update as documented in https://react-query-v3.tanstack.com/guides/optimistic-updates
// optimistic update as documented in https://react-query-v5.tanstack.com/guides/optimistic-updates
// except we do it in a mutate wrapper instead of the onMutate callback
// to have access to success side effects

Expand All @@ -365,7 +365,7 @@ export const useUpdateMany = <
* [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
* ]
*
* @see https://react-query-v3.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
* @see https://react-query-v5.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
*/
snapshot.current = queryKeys.reduce(
(prev, queryKey) =>
Expand Down
2 changes: 1 addition & 1 deletion packages/react-admin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A frontend Framework for building data-driven applications running in the browse
## Features

* Adapts to any backend (REST, GraphQL, SOAP, etc.)
* Powered by [Material UI](https://mui.com/material-ui/getting-started/), [react-query](https://react-query-v3.tanstack.com/), [react-hook-form](https://react-hook-form.com), [react-router](https://reacttraining.com/react-router/) and a few more
* Powered by [Material UI](https://mui.com/material-ui/getting-started/), [react-query](https://react-query-v5.tanstack.com/), [react-hook-form](https://react-hook-form.com), [react-router](https://reacttraining.com/react-router/) and a few more
djhi marked this conversation as resolved.
Show resolved Hide resolved
* Super-fast UI thanks to optimistic rendering (renders before the server returns)
* Undo updates and deletes for a few seconds
* Relationships (many to one, one to many)
Expand Down
Loading