You need to create dedicated component for
function useToken() {
const { getAccessTokenSilently } = useAuth0();
const [token, setToken] = useState(null);
useEffect(() => { getAccessTokenSilently().then(setToken) }, [])
return token;
}
function MyApolloProvider({ children }) {
const token = useToken();
// useRef instead of useMemo to make sure client is not re-created randomly
const clientRef = useRef(null);
if (token && !clientRef.current) {
// This code should only be executed once.
clientRef.current = new ApolloClient(/**/)
}
if (!clientRef.current) {
// Now we have to wait until client is initialized with token, so you might want to add some spinner
return null;
}
return <ApolloClient client={clientRef.current} >{children}</ApolloClient>
}
And then you use it instead of original ApolloProvider in yours ReactDOM.render.
If token changes then things become a bit more difficult.
https://www.apollographql.com/docs/react/networking/authentication/#header
You still use similar approach:
function useToken() { /* should return actual token and update it if changed */ }
function MyApolloProvider({ children }) {
const token = useToken();
const tokenRef = useRef(token);
const clientRef = useRef(null);
tokenRef.current = token; // make sure that tokenRef always has up to date token
if (!clientRef.current) {
// This function is called on each request individually and it takes token from ref
const authLink = setContext((_, { headers }) => {
// similar to documentation example, but you read token from ref
const token = tokenRef.current;
return {
headers: {
...headers,
authorization: `Bearer ${token}`,
}
}
});
clientRef.current = new ApolloClient(
link: authLink.concat(httpLink),
// ...
)
}
}
Usage in index.js
regardless of first or second case:
ReactDOM.render(
<Auth0Provider /* options */>
<MyApolloProvider>
{/* ... */}
</MyApolloProvider>
</Auth0Provider>,
document.getElementById("root")
);
Main thing here is that MyApolloProvider
should be within Auth0Provider
to gain access to the token.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…