Skip to content

Commit aa0ec8b

Browse files
committed
Make useHandleCallback compatible with StrictMode + test it
1 parent 107db17 commit aa0ec8b

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

packages/ra-core/src/auth/useHandleAuthCallback.spec.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,28 @@ describe('useHandleAuthCallback', () => {
160160
expect(abort).toHaveBeenCalled();
161161
});
162162
});
163+
164+
it('should only call handleCallback once when the component is rendered', async () => {
165+
const handleCallback = jest.spyOn(authProvider, 'handleCallback');
166+
render(
167+
<React.StrictMode>
168+
<TestMemoryRouter initialEntries={['/auth-callback']}>
169+
<AuthContext.Provider value={authProvider}>
170+
<QueryClientProvider client={new QueryClient()}>
171+
<Routes>
172+
<Route path="/" element={<div>Home</div>} />
173+
<Route
174+
path="/auth-callback"
175+
element={<TestComponent />}
176+
/>
177+
</Routes>
178+
</QueryClientProvider>
179+
</AuthContext.Provider>
180+
</TestMemoryRouter>
181+
</React.StrictMode>
182+
);
183+
184+
await screen.findByText('Home');
185+
expect(handleCallback).toHaveBeenCalledTimes(1);
186+
});
163187
});

packages/ra-core/src/auth/useHandleAuthCallback.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,38 @@ export const useHandleAuthCallback = (
2424
const nextSearch = locationState && locationState.nextSearch;
2525
const defaultRedirectUrl = nextPathName ? nextPathName + nextSearch : '/';
2626
const { onSuccess, onError, onSettled, ...queryOptions } = options ?? {};
27+
let handleCallbackPromise: Promise<void> | null;
2728

2829
const queryResult = useQuery({
2930
queryKey: ['auth', 'handleCallback'],
30-
queryFn: ({ signal }) =>
31-
authProvider && typeof authProvider.handleCallback === 'function'
32-
? authProvider
33-
.handleCallback({ signal })
34-
.then(result => result ?? null)
35-
: Promise.resolve(),
31+
queryFn: ({ signal }) => {
32+
console.log('queryFn', handleCallbackPromise);
33+
if (!handleCallbackPromise) {
34+
handleCallbackPromise = new Promise(async (resolve, reject) => {
35+
if (authProvider) {
36+
if (typeof authProvider.handleCallback === 'function') {
37+
try {
38+
const result =
39+
await authProvider.handleCallback({
40+
signal,
41+
});
42+
return resolve(result ?? null);
43+
} catch (error) {
44+
return reject({
45+
redirectTo: false,
46+
message: error.message,
47+
});
48+
}
49+
}
50+
return resolve();
51+
}
52+
return reject({
53+
message: 'Failed to handle login callback.',
54+
});
55+
});
56+
}
57+
return handleCallbackPromise;
58+
},
3659
retry: false,
3760
...queryOptions,
3861
});

0 commit comments

Comments
 (0)