最直接的方法是将 title 属性移动到 MainContent 布局包装器并单独包装每个路由,但您会丢失嵌套路由。
另一种方法是创建一个 React 上下文来保存 title 状态并使用包装器组件来设置标题。
const TitleContext = createContext({
title: "",
setTitle: () => {}
});
const useTitle = () => useContext(TitleContext);
const TitleProvider = ({ children }) => {
const [title, setTitle] = useState("");
return (
<TitleContext.Provider value={{ title, setTitle }}>
{children}
</TitleContext.Provider>
);
};
使用提供者包装应用程序(或任何高于 Routes 组件的祖先组件)。
<TitleProvider>
<App />
</TitleProvider>
更新MainContent 以访问useTitle 挂钩以获取当前title 值并呈现它。
function MainContent() {
const { title } = useTitle();
return (
<div>
<h1>{title}</h1>
<div>
<Outlet />
</div>
</div>
);
}
TitleWrapper 组件。
const TitleWrapper = ({ children, title }) => {
const { setTitle } = useTitle();
useEffect(() => {
setTitle(title);
}, [setTitle, title]);
return children;
};
并更新路由组件以包装在 TitleWrapper 组件中,在此处传递 title 属性。
<Route path="/projects" element={<MainContent />}>
<Route
index
element={
<TitleWrapper title="Projects">
<ProjectList />
</TitleWrapper>
}
/>
<Route
path="create"
element={
<TitleWrapper title="Create Project">
<CreateProject />
</TitleWrapper>
}
/>
</Route>
这样,MainContent 可以被认为是一组路由的通用 UI,而 TitleWrapper(您可以选择更合适的名称)可以被认为是特定于路由的 UI一条路线。
更新
我忘记了 Outlet 组件提供了自己的 React 上下文。这变得更微不足道了。谢谢@LIIT。
例子:
import { useOutletContext } from 'react-router-dom';
const useTitle = (title) => {
const { setTitle } = useOutletContext();
useEffect(() => {
setTitle(title);
}, [setTitle, title]);
};
...
function MainContent() {
const [title, setTitle] = useState("");
return (
<div>
<h1>{title}</h1>
<div>
<Outlet context={{ title, setTitle }} />
</div>
</div>
);
}
...
const CreateProject = ({ title }) => {
useTitle(title);
return ...;
};
...
<Router>
<Routes>
<Route path="/projects" element={<MainContent />}>
<Route index element={<ProjectList title="Projects" />} />
<Route
path="create"
element={<CreateProject title="Create Project" />}
/>
</Route>
</Routes>
</Router>