reactjs 使用导航组件的react-router v6中不同路由的模态

zsbz8rwp  于 2023-02-18  发布在  React
关注(0)|答案(1)|浏览(175)

下面是重现该问题的codesandbox
我在react-router v6源代码中使用modal example,并且我希望在模态中显示路由的内容。
我的路线定义如下:

<Routes location={state?.backgroundLocation || location}>
  <Route path="/" element={<Layout />}>
    <Route index element={<Home />} />
    <Route path="gallery/:counter" element={<Gallery />} />
    <Route path="*" element={<NoMatch />} />
  </Route>
</Routes>

{/* Show the modal when a `backgroundLocation` is set */}
{state?.backgroundLocation && (
  <Routes>
    <Route path="/modal/:counter" element={<Modal />} />
  </Routes>
)}

当用户点击Modal链接时,我想在模态中显示gallery/:counter路由的内容,但是除了使用<Navigate />组件之外,我不确定如何触发路由,这会导致整个页面重定向。

a8jjtwal

a8jjtwal1#

你不能同时匹配两个不同的URL路径,浏览器只有一个地址栏和URL,我建议创建一个布局路由组件,它 Package "/gallery/:counter"路由,并有条件地将嵌套的路由呈现到Modal组件中。
示例:

const ModalLayout = () => {
  const { state } = useLocation();

  return state?.backgroundLocation ? (
    <Modal>
      <Outlet />
    </Modal>
  ) : (
    <Outlet />
  );
};

Modal被更新为接受children prop并将children * 渲染为 * 模态内容。这是上面的Outlet被渲染的地方,以便嵌套的路由可以将它们的element内容渲染为模态。

function Modal({ children }: React.PropsWithChildren) {
  const navigate = useNavigate();
  const buttonRef = useRef<HTMLButtonElement>(null);

  function onDismiss() {
    navigate(-1);
  }

  return (
    <Dialog
      aria-labelledby="label"
      onDismiss={onDismiss}
      initialFocusRef={buttonRef}
    >
      <div
        style={{
          display: "grid",
          justifyContent: "center",
          padding: "8px 8px"
        }}
      >
        {children}
        <button
          style={{ display: "block" }}
          ref={buttonRef}
          onClick={onDismiss}
        >
          Close
        </button>
      </div>
    </Dialog>
  );
}

"/gallery/:counter"布线被包裹在ModalLayout布局布线中。

<Route element={<ModalLayout />}>
  <Route path="gallery/:counter" element={<Gallery />} />
</Route>

为了使counter状态更容易在路由组件之间共享,并且在主路由和图库路由之间切换时保持不变,我建议将counter状态从Home组件移动到另一个布局路由中,该布局路由通过其Outlet上下文向后代组件提供counter状态和setter。

const CounterLayout = () => {
  const [counter, setCounter] = useState(1);

  return <Outlet context={{ counter, setCounter }} />;
};

这 Package 了想要/需要/关心counter状态的所有路由,例如HomeGallery组件。

<Routes>
  <Route path="/" element={<Layout />}>
    <Route element={<CounterLayout />}>
      <Route index element={<Home />} />
      <Route element={<ModalLayout />}>
        <Route path="gallery/:counter" element={<Gallery />} />
      </Route>
      <Route path="*" element={<NoMatch />} />
    </Route>
  </Route>
</Routes>

第一节第一节第一节第二节第一节第三节第一

相关问题