如何访问React Router v6.4 actions
和loaders
中的Auth0访问令牌,以便调用安全的API?
我试图将getAccessTokenSilently()
方法指向加载器,但我不能在组件外部调用useAuth0()
钩子(我的路径是在组件as recommended by the react router documentation外部创建的).出于同样的原因,我不能在加载器中调用useAuth0()
:它不是一个组件.
我try 将路由放在组件中(将下面代码中显示的路由移动到<App/>
组件中),但这导致了useAuth0()
中的错误,即必须从Auth0Provider
中调用它.
官方的Auth0 guide to React Router v6还没有更新到使用createBrowserRouter
,在他们的安全API示例中也没有使用加载器.
这似乎是任何Reaction RouterV6.4应用程序的基本需求,但我从来没有找到一个示例来说明如何做到这一点.以前肯定有人这么做过吧?
Update: Thanks to the assistance of Drew this works! The below code is a full working version of this.个
Auth0ProviderWithNavigate.tsx个
interface Auth0ProviderWithNavigateProps {
children: React.ReactNode;
}
export const Auth0ProviderWithNavigate = ({
children,
}: Auth0ProviderWithNavigateProps) => {
if (
!(
ENV.VITE_AUTH0_DOMAIN &&
ENV.VITE_AUTH0_CLIENT_ID &&
ENV.VITE_AUTH0_CALLBACK_URL
)
) {
return null;
}
return (
<Auth0Provider
domain={ENV.VITE_AUTH0_DOMAIN}
clientId={ENV.VITE_AUTH0_CLIENT_ID}
authorizationParams={{
redirect_uri: ENV.VITE_AUTH0_CALLBACK_URL,
}}
>
{children}
</Auth0Provider>
);
};
AuthenticationGuard.tsx
import { withAuthenticationRequired } from "@auth0/auth0-react";
import { PageLoader } from "./PageLoader";
interface AuthenticationGuardProps {
component: React.ComponentType<object>;
}
export const AuthenticationGuard = ({
component,
}: AuthenticationGuardProps) => {
const Component = withAuthenticationRequired(component, {
onRedirecting: () => <PageLoader />,
});
return <Component />;
};
main.tsx个
const root = document.getElementById("root");
root &&
ReactDOM.createRoot(root).render(
<React.StrictMode>
<AppContextProvider>
<Auth0ProviderWithNavigate>
<AppTheme>
<App />
</AppTheme>
</Auth0ProviderWithNavigate>
</AppContextProvider>
</React.StrictMode>
);
App.tsx个
const App = () => {
const { getAccessTokenSilently } = useAuth0();
const router = useMemo(() => {
return createBrowserRouter([
{
children: [
{
path: "/",
element: <WelcomePage />,
errorElement: <ErrorPage />,
},
{
children: [
{
id: "edct",
path: "/edct",
element: <AuthenticationGuard component={Edct} />,
errorElement: <ErrorPage />,
loader: AirportCodesLoader({ getAccessTokenSilently }),
},
],
},
],
},
]);
}, [getAccessTokenSilently]);
return <RouterProvider router={router} />;
};
export default App;
AirportCodesLoader.tsx个
import { ActionFunction } from "react-router";
const cleanCodes = (codes: string | null): string | null => {
if (!codes) {
return null;
}
return codes
.split(",")
.map((code) => code.trim())
.join(",");
};
interface AppAction {
getAccessTokenSilently: () => Promise<string>;
}
export const AirportCodesLoader =
({ getAccessTokenSilently }: AppAction): ActionFunction =>
async ({ request }) => {
const url = new URL(request.url);
console.log(await getAccessTokenSilently());
return {
departureCodes: cleanCodes(url.searchParams.get("departureCodes")) ?? "",
arrivalCodes: cleanCodes(url.searchParams.get("arrivalCodes")) ?? "",
};
};