You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Material UI标签页嵌套React Router Dom路由,页面刷新异常问题

解决Material UI标签页结合React Router嵌套路由刷新时内容重叠问题

问题根源

  1. 父路由/account的关联组件中直接渲染了General组件,导致访问子路由(如/account/password)时,父组件的General与子路由的EditPassword会同时显示。
  2. Tabs的选中状态和路由未完全绑定,刷新时状态重置,引发多Tab内容同时展示的问题。

解决方案

步骤1:调整路由配置,添加默认子路由

将General设为/account的默认子路由,替代原有的硬编码渲染方式:

// App.js
<Route path="/account" element={user ? <Settings /> : <Register />}>
  {/* 匹配/account时默认渲染General */}
  <Route index element={<General />} />
  <Route path="/account/profile" element={<EditProfile />} />
  <Route path="/account/password" element={<EditPassword />} />
  <Route path="/account/social_profiles" element={<SocialProfiles />} />
  <Route path="/account/notifications" element={<EditNotifications />} />
</Route>

步骤2:重构VerticalTabs组件,绑定路由与标签状态

使用React Router的useLocation和Outlet,让标签选中状态与路由同步,同时通过Outlet渲染子路由内容:

// VerticalTabs.jsx
import { useLocation, Outlet, useNavigate } from 'react-router-dom';
import { Tabs, Tab, Box } from '@mui/material';

function VerticalTabs() {
  const location = useLocation();
  const navigate = useNavigate();

  // 根据当前路由匹配标签索引
  const getTabIndex = () => {
    switch(location.pathname) {
      case '/account/profile': return 1;
      case '/account/password': return 2;
      case '/account/social_profiles': return 3;
      case '/account/notifications': return 4;
      default: return 0;
    }
  };

  const value = getTabIndex();

  const handleChange = (event, newValue) => {
    // 根据索引跳转对应路由
    const paths = [
      '/account',
      '/account/profile',
      '/account/password',
      '/account/social_profiles',
      '/account/notifications'
    ];
    navigate(paths[newValue]);
  };

  const a11yProps = (index) => ({
    id: `vertical-tab-${index}`,
    'aria-controls': `vertical-tabpanel-${index}`,
  });

  return (
    <Box sx={{ flexGrow: 1, display: 'flex', height: '100%' }}>
      <Tabs
        orientation="vertical"
        variant="scrollable"
        value={value}
        onChange={handleChange}
        aria-label="Vertical tabs example"
        sx={{ borderRight: 1, borderColor: 'divider' }}
      >
        <Tab label="General" {...a11yProps(0)} />
        <Tab label="Edit Profile" {...a11yProps(1)} />
        <Tab label="Password" {...a11yProps(2)} />
        <Tab label="Social Profiles" {...a11yProps(3)} />
        <Tab label="Notifications" {...a11yProps(4)} />
        <Tab label="Sessions" {...a11yProps(5)} />
        <Tab label="Delete Account" {...a11yProps(6)} />
      </Tabs>
      {/* 渲染当前匹配的子路由内容 */}
      <Box sx={{ p: 3, flexGrow: 1 }}>
        <Outlet />
      </Box>
    </Box>
  );
}

export default VerticalTabs;

步骤3:简化Settings组件结构

确保Settings组件仅负责渲染VerticalTabs(已包含Outlet):

// Settings.jsx
import VerticalTabs from './VerticalTabs';

function Settings() {
  return (
    <div style={{ width: '100%', height: '100vh' }}>
      <VerticalTabs />
    </div>
  );
}

修改后效果:

  • 刷新页面时,路由直接匹配对应子路由,Outlet仅渲染当前子路由组件,不会出现内容重叠。
  • 标签选中状态完全由路由决定,刷新后自动同步到对应标签,避免状态不一致问题。

内容的提问来源于stack exchange,提问作者sultan.h

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:50:24