如何结合MUI-Lab-Tabs与React Router V6实现ScrollRestoration滚动位置保存
解决MUI Tabs结合React Router V6的滚动位置保存问题
问题背景
我使用MUI Lab的无障碍Tabs组件结合React Router V6实现路由切换,代码如下:
const tabs = [ {value: "/", label: "home"}, {value: "/hot-hub", label: "hot hub post"}, {value: "/source", label: "Source"}, {value: "/article", label: "artcile"} ] const MobileMain = memo(({}: Props) => { const navigate = useNavigate() const location = useLocation() const tabPanelSX = {height: "100%", padding: 0} return ( <div className="h-full flex flex-col"> <TabContext value={location.pathname}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <TabList onChange={(e, value) => { navigate(value) }}> {tabs.map(tab => <Tab key={tab.value} value={tab.value} label={tab.label}/>)} </TabList> </Box> {tabs.map(tab => <TabPanel key={tab.value} value={tab.value} sx={tabPanelSX}><Outlet/></TabPanel>)} </TabContext> </div> ) })
我希望用React Router V6的ScrollRestoration组件保存各标签页的滚动位置,切换标签后返回时保持原位置,但目前把它放在RouterProvider外部:
root.render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> <ScrollRestoration /> </Provider> </React.StrictMode> )
不清楚该组件的正确位置和根路由定义,求正确配置方法。
解决方案
1. 正确放置ScrollRestoration组件
ScrollRestoration必须放在React Router的上下文范围内,也就是RouterProvider内部的根路由组件中,不能放在RouterProvider外面。它需要访问路由上下文来监听位置变化,完成滚动位置的保存与恢复。
2. 定义根路由组件
创建一个根路由组件作为所有页面的容器,在其中渲染ScrollRestoration:
import { ScrollRestoration, Outlet } from "react-router-dom"; function RootLayout() { return ( <div> {/* 可放置全局导航、页头等公共组件 */} <Outlet /> {/* 渲染匹配的子路由内容 */} <ScrollRestoration /> </div> ); }
3. 调整路由配置
更新路由配置,让根路由指向RootLayout,将各个标签页的路由作为根路由的子路由:
import { createBrowserRouter } from "react-router-dom"; import RootLayout from "./RootLayout"; import MobileMain from "./MobileMain"; // 导入各标签页对应的组件 import Home from "./Home"; import HotHub from "./HotHub"; import Source from "./Source"; import Article from "./Article"; const router = createBrowserRouter([ { path: "/", element: <RootLayout />, children: [ { path: "/", element: <MobileMain />, children: [ { index: true, element: <Home /> }, { path: "hot-hub", element: <HotHub /> }, { path: "source", element: <Source /> }, { path: "article", element: <Article /> }, ], }, ], }, ]);
4. 确保MobileMain的Outlet对应正确子路由
MobileMain组件中的Outlet会自动渲染当前匹配的子路由组件(如Home、HotHub等),每个标签页内容作为独立路由组件存在,ScrollRestoration就能针对不同路径保存对应的滚动位置。
5. 更新根渲染逻辑
移除RouterProvider外部的ScrollRestoration,确保只在根路由组件中渲染一次:
root.render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> </Provider> </React.StrictMode> );
完成以上配置后,切换标签页时React Router会自动保存每个路径的滚动位置,返回标签页时会恢复到之前的滚动位置。
内容的提问来源于stack exchange,提问作者SageJustus
相关产品推荐
相关产品推荐

