I have a React SPA with following top-level structure. I'm using Auth0 for authentication and Apollo Client for queries and React Context to provide a global state.
The problem I'm having is that a query made in my global state is executing before the Apollo Client can complete configuration of its header (namely, inserting a token via Auth0).
Is there a way (perhaps using the useApolloClient hook to tell if Apollo has a token in its authLink? Or another way to achieve the objective of delaying initialization of Global State until its parent component AuthorizedApolloProvider has completed?
<BrowserRouter> <Auth0ProviderWithHistory> <AuthorizedApolloProvider> <GlobalState> <App /> </GlobalState> </AuthorizedApolloProvider> </Auth0ProviderWithHistory> </BrowserRouter>
Within AuthorizedApolloProvider, I am setting context for Apollo by inserting a token on all queries as follows:
const AuthorizedApolloProvider = ({children}) => { const { getAccessTokenSilently } = useAuth0() const httpLink = createHttpLink ({ uri: uriGQL, // a config parameter }) const authLink = setContext(async () => { const token = await getAccessTokenSilently() console.log('Got the token..... ', token.substring(0, 10)) return { headers: { authorization: token ? token : "" } } }) let links = [authLink, httpLink] const client = new ApolloClient({ link: ApolloLink.from(links), cache: new InMemoryCache({ addTypename: false, }), }) console.log('Rendering ApolloProvider') return( <ApolloProvider client={client}> {children} </ApolloProvider> ) }
Next, in Global State, I am sending a GQL query to fetch information about the user who has logged in as follows:
const GlobalState = props => { const { user: auth0User, isLoading, isAuthenticated } = useAuth0() const client = useApolloClient() const [state, setState] = useState(initialState) const [ getUser, { loading, data, error }] = useLazyQuery(GET_USER) const history = useHistory() useEffect(async () => { // Has useAuth0 returned? if(isLoading===false) { console.log('isAuthenticated=', isAuthenticated) console.log('auth0User', auth0User) // Is authenticated? if(!isAuthenticated) { // If not authenticated... console.log('Not authenticated') localStorage.removeItem('user') setState({ ...state, loaded: true, user: null }) } else { // If authenticated... // Check to see if user object is in local storage let user = await localStorage.getItem('user') if(user) { console.log('Authenticated, found user in local storage') // User found in local storage user = JSON.parse(user) setState({ ...state, loaded: true, user: user }) } else { // User not found in local storage. Must fetch from server console.log('Authenticated, getting user from server') try { console.log('Calling getUser...') const result = await getUser() } catch (error) { console.log(error) } } } } }, [isLoading]) ...
The problem I'm having is that the getUser query is being called before the Apollo client can finish configuring.
When I run the code, I see that the below fragment...
try { console.log('Calling getUser...') const result = await getUser() }
...is being executed before the following...
console.log('Got the token..... ', token.substring(0, 10)) return { headers: { authorization: token ? token : "" } }
https://stackoverflow.com/questions/67378001/detecting-if-apollo-has-finished-configuration-before-allowing-queries May 04, 2021 at 10:24AM
没有评论:
发表评论