From e93343b48cd1964cdf2c0b4a6ad24a83a3c3b0af Mon Sep 17 00:00:00 2001 From: Adam Mcgrath Date: Thu, 28 Apr 2022 16:05:11 +0100 Subject: [PATCH] Make sure handleRedirectCallback is only called once in StrictMode React 18 (#355) * HandleRedirectCallback can only be called once in React 18 StrictMode * Remove unnessesary assert --- __tests__/auth-provider.test.tsx | 24 +++++++++++++++++++++++- src/auth0-provider.tsx | 6 ++++++ static/index.html | 23 +++++++++++++---------- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/__tests__/auth-provider.test.tsx b/__tests__/auth-provider.test.tsx index 06aaf430..3451801c 100644 --- a/__tests__/auth-provider.test.tsx +++ b/__tests__/auth-provider.test.tsx @@ -1,5 +1,6 @@ -import { useContext } from 'react'; +import React, { StrictMode, useContext } from 'react'; import Auth0Context from '../src/auth0-context'; +import { render, waitFor } from '@testing-library/react'; import { renderHook, act } from '@testing-library/react-hooks'; import { Auth0Client, @@ -7,6 +8,7 @@ import { } from '@auth0/auth0-spa-js'; import pkg from '../package.json'; import { createWrapper } from './helpers'; +import { Auth0Provider } from '../src'; const clientMock = jest.mocked(new Auth0Client({ client_id: '', domain: '' })); @@ -854,4 +856,24 @@ describe('Auth0Provider', () => { expect(result.current).toBe(memoized); }); + + it('should only handle redirect callback once', async () => { + window.history.pushState( + {}, + document.title, + '/?code=__test_code__&state=__test_state__' + ); + clientMock.handleRedirectCallback.mockResolvedValue({ + appState: undefined, + }); + render( + + + + ); + await waitFor(() => { + expect(clientMock.handleRedirectCallback).toHaveBeenCalledTimes(1); + expect(clientMock.getUser).toHaveBeenCalled(); + }); + }); }); diff --git a/src/auth0-provider.tsx b/src/auth0-provider.tsx index 6793c7c3..d4809f0b 100644 --- a/src/auth0-provider.tsx +++ b/src/auth0-provider.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useMemo, useReducer, + useRef, useState, } from 'react'; import { @@ -240,8 +241,13 @@ const Auth0Provider = (opts: Auth0ProviderOptions): JSX.Element => { () => new Auth0Client(toAuth0ClientOptions(clientOpts)) ); const [state, dispatch] = useReducer(reducer, initialAuthState); + const didInitialise = useRef(false); useEffect(() => { + if (didInitialise.current) { + return; + } + didInitialise.current = true; (async (): Promise => { try { if (hasAuthParams() && !skipRedirectCallback) { diff --git a/static/index.html b/static/index.html index a09f009e..03ce7503 100644 --- a/static/index.html +++ b/static/index.html @@ -133,19 +133,22 @@ }; return ( - - - + + + + + ); }; - ReactDOM.render(, document.getElementById('app')); + const root = ReactDOM.createRoot(document.getElementById('app')); + root.render();