首页 > 解决方案 > React、单页应用程序和浏览器的后退按钮

问题描述

我知道我的问题可能只是“这无法完成,这定义了 SPA 的目的”。但...

mydomain.com我在我的 REACT 网络应用程序中导航到。此页面从后端加载数据并填充精细的网格。加载和渲染大约需要 2 秒。

现在,我单击该详细页面上的链接并导航到mydomain.com/otherPage. 当我单击浏览器的 BACK 按钮返回到 时mydomain.com,它是空白的,并且必须从头开始重建,因为 SPA 规定必须在每次页面更改时擦除和重建 DOM(至少是页面特定的动态部分,如路线可以在页眉/页脚等的固定布局内)。我明白了...

除了迁移到 nextJS 和使用 SSR....

REACT 中是否有任何神奇的解决方案可以在导航出页面时以某种方式“保留”页面的 DOM,以便当您浏览器返回该页面时,该页面会立即显示而不是从头开始呈现?

标签: javascriptreactjsnext.jssingle-page-application

解决方案


是的,在保持 DOM 呈现但隐藏的同时切换路由是很有可能的!如果您正在构建一个 SPA,那么使用客户端路由是一个好主意。这使您的任务变得简单:

要隐藏,同时将组件保留在 DOM 中,请使用以下任一 css:

  1. .hidden { visibility: hidden }仅隐藏未使用的组件/路由,但仍保留其布局。

  2. .no-display { display: none }隐藏未使用的组件/路由,包括其布局。

对于路由,使用react-router-dom,您可以在组件上使用函数 children propRoute

孩子们:功能

有时您需要渲染路径是否与位置匹配。在这些情况下,您可以使用功能 children 道具。它的工作原理与render 完全一样,只是无论是否匹配都会被调用。children 渲染道具接收与组件和渲染方法相同的所有路由道具,除非当路由无法匹配 URL 时,匹配为空。这允许您根据路由是否匹配来动态调整 UI。

在我们的例子中,如果路由不匹配,我将添加隐藏的 css 类:

应用程序.tsx:

export default function App() {
  return (
    <div className="App">
      <Router>
        <HiddenRoutes hiddenClass="hidden" />
        <HiddenRoutes hiddenClass="no-display" />
      </Router>
    </div>
  );
}

const HiddenRoutes: FC<{ hiddenClass: string }> = ({ hiddenClass }) => {
  return (
    <div>
      <nav>
        <NavLink to="/1">to 1</NavLink>
        <NavLink to="/2">to 2</NavLink>
        <NavLink to="/3">to 3</NavLink>
      </nav>
      <ol>
        <Route
          path="/1"
          children={({ match }) => (
            <li className={!!match ? "" : hiddenClass}>item 1</li>
          )}
        />
        <Route
          path="/2"
          children={({ match }) => (
            <li className={!!match ? "" : hiddenClass}>item 2</li>
          )}
        />
        <Route
          path="/3"
          children={({ match }) => (
            <li className={!!match ? "" : hiddenClass}>item 3</li>
          )}
        />
      </ol>
    </div>
  );
};

样式.css:

.hidden {
  visibility: hidden;
}
.no-display {
  display: none;
}

工作 CodeSandbox:https ://codesandbox.io/s/hidden-routes-4mp6c?file=/src/App.tsx

比较visibility: hiddenvs.的不同行为display: none

请注意,在这两种情况下,所有组件仍然安装到 DOM!您可以使用浏览器开发工具中的检查工具进行验证。

可重复使用的解决方案

对于可重用的解决方案,您可以创建可重用的HiddenRoute组件。

在下面的示例中,我使用了 hook useRouteMatch,类似于childrenRoute 道具的工作方式。基于匹配,我为新组件子项提供隐藏类:

import "./styles.css";
import {
  BrowserRouter as Router,
  NavLink,
  useRouteMatch,
  RouteProps
} from "react-router-dom";

// Reusable components that keeps it's children in the DOM
const HiddenRoute = (props: RouteProps) => {
  const match = useRouteMatch(props);
  return <span className={match ? "" : "no-display"}>{props.children}</span>;
};

export default function App() {
  return (
    <div className="App">
      <Router>
        <nav>
          <NavLink to="/1">to 1</NavLink>
          <NavLink to="/2">to 2</NavLink>
          <NavLink to="/3">to 3</NavLink>
        </nav>
        <ol>
          <HiddenRoute path="/1">
            <li>item 1</li>
          </HiddenRoute>
          <HiddenRoute path="/2">
            <li>item 2</li>
          </HiddenRoute>
          <HiddenRoute path="/3">
            <li>item 3</li>
          </HiddenRoute>
        </ol>
      </Router>
    </div>
  );
}  

可重用解决方案的工作 CodeSandbox:https ://codesandbox.io/s/hidden-routes-2-3v22n?file=/src/App.tsx


推荐阅读