这是我的index.tsx
import ReactDOM from 'react-dom/client';
import App from './App';
import { PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider } from '@azure/msal-react';
import { msalConfig } from './azureAuthConfig';
const msalInstance = new PublicClientApplication(msalConfig);
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<MsalProvider instance={msalInstance}>
<App />
</MsalProvider>
);
这是我的应用程序.tsx
import { BrowserRouter, Routes, Route } from "react-router-dom"
import './App.css';
import Layout from './components/Layout';
import Home from './components/Home';
import AuthRequired from './components/AuthRequired';
import Usage from "./components/Usage";
import Login from "./components/Login";
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route element={<AuthRequired />} >
<Route path="usage" element={<Usage />} />
</Route>
<Route path="/login" element={<Login />} />
</Route>
</Routes>
</BrowserRouter >
);
}
这是我的布局组件,我在其中定义了一些出口上下文
import React from 'react';
import Header from "./Header"
import Footer from "./Footer"
import { Outlet } from 'react-router-dom';
import { ReportingPeriod, SelectedProjects } from '../types';
import { DefaultReportingPeriod } from '../utils';
export default function Layout() {
// Set Context for the Pollination key
const [pollinationKey, setPollinationKey] = React.useState<string>("")
// Set reporting period to be used on the rest of the app
const [reportingPeriod, setReportingPeriod] = React.useState<ReportingPeriod>({
start: DefaultReportingPeriod().start,
end: DefaultReportingPeriod().end
});
// Set Project names to be used on the rest of the app
const [selectedProjects, setSelectedProjects] = React.useState<SelectedProjects>({});
return (
<>
<Header />
<Outlet context={{
pollinationKey, setPollinationKey,
reportingPeriod, setReportingPeriod,
selectedProjects, setSelectedProjects
}} />
<Footer />
</>
)
}
我发现我可以在登录路由上成功访问此上下文,但不能在受保护的使用路由上成功访问此上下文。为什么会这样?
这是我尝试访问其中一个上下文值时遇到的错误
Uncaught TypeError: Cannot destructure property 'reportingPeriod' of '(0 , react_router_dom__WEBPACK_IMPORTED_MODULE_5__.useOutletContext)(...)' as it is undefined.
我尝试了以下方法:
根据documentation的建议,我确实在布局组件上创建了一个钩子以在使用组件中使用。没用。结果相同。
我尝试将Usage路由从受保护的路由中取出只是为了测试。有效。我能够访问该值。
如果我使用 React 的 Context API 并使用上下文提供程序包装 BrowserRouter,如下所示。它有效。
export default function App() {
return (
<AppProvider>
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route element={<AuthRequired />} >
<Route path="usage" element={<Usage />} />
</Route>
<Route path="/login" element={<Login />} />
</Route>
</Routes>
</BrowserRouter >
</AppProvider>
);
}
如上所述,我真的很想使用React Router V6的outletContext来实现这个功能。
Layout
和
AuthRequired
都应该渲染
Outlets
组件。问题似乎是您直接在叶路由组件中通过
reportingPeriod
解构
useOutletContext
,例如
Usage
。
useOutletContext
钩子访问最近祖先
Outlet
组件的上下文值,例如
AuthRequired
提供的。您可以更新
AuthRequired
以访问任何祖先
Outlet
上下文并沿着 ReactTree 向下转发。示例:
export default function Layout() {
...
return (
<>
<Header />
<Outlet
context={{
pollinationKey,
setPollinationKey,
reportingPeriod,
setReportingPeriod,
selectedProjects,
setSelectedProjects
}}
/>
<Footer />
</>
)
}
const AuthRequired = () => {
const context = useOutletContext(); // <-- any ancestor context value
... AuthRequired business logic ...
return <someCondition>
? (
<Outlet
context={{
...context, // <-- shallow copy ancestor context value
// add any new context value
}}
/>
) : <Navigate to="/login" replace />;
};
const Usage = () => {
const { reportingPeriod } = useOutletContext();
...
};