如何使用 React Router 创建响应式主细节应用程序?

问题描述 投票:0回答:2

我在 Github 上准备了 一个简单的测试用例来回答我的问题:

RouterLayout.jsx 中,媒体查询使

Outlet
在窄屏幕上消失,如动画屏幕截图中所示,我拖动浏览器一侧以使其变小:

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 或其他页面,并且可以返回到主列表。这还行不通。

平板电脑和计算机屏幕上,主列表和第 1 页或其他内容彼此靠近显示。这已经在我的代码中起作用了。

我应该向下面的

MasterList.jsx
中的 Link 添加一些属性吗?

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;
reactjs react-router responsive-design react-router-dom master-detail
2个回答
1
投票

在未渲染

Outlet
的较小视图尺寸上,嵌套的
Route
组件不再有地方渲染其
element
内容。如果我正确理解你的帖子,你想在较大的非“移动”视图尺寸上使用
RootLayout
Outlet
,并且在移动视图尺寸上将
RootLayout
渲染为同级路线而不是父路线,所以所有其他路线都可以到达。

重构示例:

  • 创建两个根布局,移动和非移动。

    function RootLayout() {
      return (
        <div
          style={{
            display: "flex",
            justifyContent: "space-around",
            alignItems: "flex-start"
          }}
        >
          <MasterList />
          <div>
            <h3>Detail</h3>
            <Outlet />
          </div>
        </div>
      );
    }
    
    function MobileLayout() {
      return (
        <div
          style={{
            display: "flex",
            justifyContent: "space-around",
            alignItems: "flex-start"
          }}
        >
          <div>
            <h3>Detail</h3>
            <Outlet />
          </div>
        </div>
      );
    }
    
  • 更新

    App
    以使用媒体查询挂钩并有条件地渲染一个根布局或另一种,并有条件地将
    MasterList
    渲染为较小屏幕上的索引路由。

    export default function App() {
      const isSmallScreen = useMediaQuery("(max-width: 768px)");
    
      const router = React.useMemo(
        () =>
          createBrowserRouter(
            createRoutesFromElements(
              <Route
                path="/"
                element={isSmallScreen ? <MobileLayout /> : <RootLayout />}
              >
                {isSmallScreen && <Route index element={<MasterList />} />}
                <Route path="page1" element={<Page1 />} />
                <Route path="page2" element={<Page2 />} />
                <Route path="page3" element={<Page3 />} />
                <Route path="*" element={<Page4 />} />
              </Route>
            )
          ),
        [isSmallScreen]
      );
    
      return <RouterProvider router={router} />;
    }
    

0
投票

我不知道实现此目的的最佳方法是什么,但它需要结合 Outlet 在父组件中渲染子路由的事实。

我会探索 useMatches 看看是否可以使用它来确定父组件是在

/parent
还是
/parent/child
上渲染。有了这些信息,您就可以有条件地渲染导航元素:

  • 如果在 /parent 上,则始终呈现导航
  • 如果在 /parent/child 且屏幕较小,则不渲染导航
  • 始终渲染 Outlet
© www.soinside.com 2019 - 2024. All rights reserved.