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

如何使用React Router创建响应式主详情应用?

响应式主详情布局问题

我准备了一个测试用例,动态效果如下:
动态截图

在RootLayout.jsx中,通过媒体查询在窄屏(≤768px)时隐藏Outlet,拖动浏览器窗口缩小就能看到这个效果:

// RootLayout.jsx
import { Outlet } from "react-router";
import { useMediaQuery } from "@react-hook/media-query";
import MasterList from "../components/MasterList";

export default function RootLayout() {
  const isSmallScreen = useMediaQuery("(max-width: 768px)");

  return (
    <div
      style={{
        display: "flex",
        justifyContent: "space-around",
        alignItems: "flex-start",
      }}
    >
      <MasterList />
      {!isSmallScreen && (
        <div>
          <h3>Detail</h3>
          <Outlet />
        </div>
      )}
    </div>
  );
}

问题描述

  • 大屏(平板/电脑):主列表和详情页(Page1等)并排显示,此功能已实现。
  • 小屏(手机):仅显示主列表,点击链接后需展示对应详情页,且支持返回主列表,但目前该功能未实现。

请问是否需要给MasterList.jsx中的Link添加额外属性?

// MasterList.jsx
import { Link } from "react-router-dom";

const MasterList = () => {
  const pages = [
    { id: 1, title: "Page 1" },
    { id: 2, title: "Page 2" },
    { id: 3, title: "Page 3" },
    { id: 4, title: "Page 4" },
  ];

  return (
    <div>
      <h2>Master List</h2>
      <nav>
        <ul>
          {pages.map((page) => (
            <li key={page.id}>
              <Link to={"/page" + page.id}>{page.title}</Link>
            </li>
          ))}
        </ul>
      </nav>
    </div>
  );
};

export default MasterList;
// App.jsx
import {
  Route,
  RouterProvider,
  createBrowserRouter,
  createRoutesFromElements,
} from "react-router-dom";
import Page1 from "./pages/Page1";
import Page2 from "./pages/Page2";
import Page3 from "./pages/Page3";
import Page4 from "./pages/Page4";
import RootLayout from "./layouts/RootLayout";

const router = createBrowserRouter(
  createRoutesFromElements(
    <Route path="/" element={<RootLayout />}>
      <Route path="page1" element={<Page1 />} />
      <Route path="page2" element={<Page2 />} />
      <Route path="page3" element={<Page3 />} />
      <Route path="*" element={<Page4 />} />
    </Route>
  )
);

const App = () => {
  return <RouterProvider router={router} />;
};

export default App;

解决方案

不需要给Link添加任何额外属性,问题根源在RootLayout的渲染逻辑——窄屏时你完全隐藏了Outlet,导致路由切换到详情页后没有容器渲染内容。

调整RootLayout的逻辑,让它根据屏幕尺寸和当前路由动态切换显示内容:

// 修改后的 RootLayout.jsx
import { Outlet, useLocation, useNavigate } from "react-router";
import { useMediaQuery } from "@react-hook/media-query";
import MasterList from "../components/MasterList";

export default function RootLayout() {
  const isSmallScreen = useMediaQuery("(max-width: 768px)");
  const location = useLocation();
  const navigate = useNavigate();
  const isOnDetailPage = location.pathname !== "/";

  // 小屏设备逻辑
  if (isSmallScreen) {
    if (isOnDetailPage) {
      // 详情页:显示返回按钮+详情内容
      return (
        <div>
          <button onClick={() => navigate("/")}>返回主列表</button>
          <h3>Detail</h3>
          <Outlet />
        </div>
      );
    } else {
      // 根路径:仅显示主列表
      return <MasterList />;
    }
  }

  // 大屏设备逻辑:保持主列表与详情页并排
  return (
    <div
      style={{
        display: "flex",
        justifyContent: "space-around",
        alignItems: "flex-start",
      }}
    >
      <MasterList />
      <div>
        <h3>Detail</h3>
        <Outlet />
      </div>
    </div>
  );
}

核心逻辑说明

  1. 用useLocation判断当前是否处于详情页路由
  2. 小屏时:
    • 若在详情页,渲染返回按钮+详情内容(通过Outlet)
    • 若在根路径,仅渲染主列表
  3. 大屏时维持原有并排布局不变

这样调整后,小屏点击Link会正常跳转到详情页,点击返回按钮能回到主列表,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 13:55:04