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

如何从嵌套路由向页面布局的其他区域传递元素?

实现带动态侧边栏/页眉的嵌套路由布局方案

核心思路

React Router 的 Route 组件不支持自定义属性(比如你伪代码里的sidebar/header),我们需要通过上下文(Context)+ 路由包装组件的方式,把父路由定义的侧边栏、页眉传递给顶层布局组件,同时保持布局和内容的解耦。


步骤1:创建布局上下文

定义一个上下文,用来存储当前路由对应的侧边栏和页眉组件:

// src/contexts/LayoutContext.tsx
import { createContext, useContext, ReactNode } from 'react';

type LayoutContextType = {
  sidebar: ReactNode | null;
  header: ReactNode | null;
};

const LayoutContext = createContext<LayoutContextType>({
  sidebar: null,
  header: null,
});

export const LayoutProvider = LayoutContext.Provider;
export const useLayout = () => useContext(LayoutContext);

步骤2:改造布局组件

修改DefaultLayout,通过上下文获取侧边栏和页眉并渲染:

// src/layouts/DefaultLayout.tsx
import { Outlet } from 'react-router-dom';
import { useLayout } from '../contexts/LayoutContext';

export function DefaultLayout() {
  const { sidebar, header } = useLayout();

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      {/* 渲染侧边栏 */}
      {sidebar && <div className="sidebar">{sidebar}</div>}
      
      <div className="page" style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>
        {/* 渲染页眉 */}
        {header && <div className="page-header">{header}</div>}
        
        {/* 渲染子路由内容 */}
        <div className="page-body" style={{ flex: 1, overflow: 'auto' }}>
          <Outlet />
        </div>
      </div>
    </div>
  );
}

步骤3:创建路由包装组件

写一个自定义路由包装组件,用来接收sidebar/header属性,并通过上下文传递给布局:

// src/components/RouteWithLayout.tsx
import { Route, RouteProps } from 'react-router-dom';
import { LayoutProvider } from '../contexts/LayoutContext';
import { ReactNode } from 'react';

type RouteWithLayoutProps = RouteProps & {
  sidebar?: ReactNode;
  header?: ReactNode;
};

export function RouteWithLayout({ sidebar, header, ...props }: RouteWithLayoutProps) {
  return (
    <LayoutProvider value={{ sidebar: sidebar || null, header: header || null }}>
      <Route {...props} />
    </LayoutProvider>
  );
}

步骤4:配置路由

用RouteWithLayout代替原生Route,在父路由里定义对应的侧边栏和页眉:

// src/routes/AppRoutes.tsx
import { Routes } from 'react-router-dom';
import { DefaultLayout } from '../layouts/DefaultLayout';
import { RouteWithLayout } from '../components/RouteWithLayout';

// 导入你的页面组件
import DefaultSidebar from '../components/DefaultSidebar';
import DashboardHeader from '../components/DashboardHeader';
import DashboardHomePage from '../pages/DashboardHomePage';
import DashboardStatsPage from '../pages/DashboardStatsPage';
import DashboardHelpPage from '../pages/DashboardHelpPage';
import UserSidebar from '../components/UserSidebar';
import UserHeader from '../components/UserHeader';
import UserOverviewPage from '../pages/UserOverviewPage';
import UserAccountsPage from '../pages/UserAccountsPage';

export function AppRoutes() {
  return (
    <Routes>
      <Route element={<DefaultLayout />}>
        {/* Dashboard 分组路由,带专属侧边栏和页眉 */}
        <RouteWithLayout
          path="/dashboard"
          sidebar={<DefaultSidebar />}
          header={<DashboardHeader />}
        >
          <Route index element={<DashboardHomePage />} />
          <Route path="stats" element={<DashboardStatsPage />} />
          <Route path="help" element={<DashboardHelpPage />} />
        </RouteWithLayout>

        {/* User 分组路由,带专属侧边栏和页眉 */}
        <RouteWithLayout
          path="/user"
          sidebar={<UserSidebar />}
          header={<UserHeader />}
        >
          <Route index element={<UserOverviewPage />} />
          <Route path="accounts" element={<UserAccountsPage />} />
        </RouteWithLayout>
      </Route>
    </Routes>
  );
}

避免无限循环的注意事项

  1. 不要在路由配置里动态创建组件实例(比如不要写sidebar={() => <DefaultSidebar />}),直接传递组件实例即可。
  2. 如果侧边栏/页眉是复杂组件,建议用React.memo包裹,避免不必要的重渲染。

内容的提问来源于stack exchange,提问作者Katai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 12:30:24