带有惰性和 Suspense 的 React 路由器总是在页面刷新时退回到通配符路由

React router with lazy and Suspense always falls back on wildcard route on page refresh

为了减少主包的大小,我用 lazy 和 suspense 实现了延迟加载路由。

但是,我 运行 遇到了一个问题,即在刷新页面时,应用程序总是以通配符路径结束,而不是在当前位置重新加载 url。

如果我删除通配符,问题似乎就解决了,但后来我错过了在错误 url 输入时被重定向的行为。 如果我删除 lazy/suspense 组合并在主包上加载路由,问题也得到解决,但显然我失去了延迟加载的好处。

这是为什么?可以做些什么来让刷新在以前的路线上结束?

// Lazy imports
const Home = lazy(() => import("./home/Home"));
const RecordsModule = lazy(() => import("./records/Records"));

function App() {
  // ...some logic
  // No use of lazy loading here
  return (
    <BrowserRouter>
      <Switch>
        <Route exact path="/">
          <Redirect to={isLoggedIn ? "/main" : "/auth"} />
        </Route>
        <Route path="/auth">
          <Auth />
        </Route>
        <Route path="/main">
          {!isLoggedIn && <Redirect to="/auth" />}
          <Main />
        </Route>
        <Route path="*">
          <Redirect to="/" />
        </Route>
      </Switch>
      <Toaster />
    </BrowserRouter>
  );
}

function Main() {
  // ...some other logic
  /*
    Here the Home and RecordsModule components are lazy loaded.
    If the user refreshes the page while being on /main/records,
    the resulting refresh will bring him on /main/home.
    
    If I put a console.log in the wildcard route,
    it appears to be the route used after the refresh.
    
    The issue is not present if not using lazy loading or removing the wildcard route.
  */
  return (
    <div className="main">
      <Switch>
        <ErrorBoundary>
          <Suspense
            fallback={
              <FullPageContainer>
                <Spinner />
              </FullPageContainer>
            }
          >
            {/* This will redirect to /main/home if coming from /main  */}
            <Route exact path={match.path}>
              <Redirect to={`${match.path}/home`} />
            </Route>
            {/* /main/home */}
            <Route path={`${match.path}/home`}>
              <Home />
            </Route>
            {/* /main/records */}
            <Route path={`${match.path}/records`}>
              <RecordsModule />
            </Route>
            {/* Redirects to /main/home if none of the above is matched */}
            <Route path="*">
              <Redirect to={`${match.path}/home`} />
            </Route>
          </Suspense>
        </ErrorBoundary>
      </Switch>
      <Menu />
    </div>
  );
}

通过迁移到 React 路由器 v6 解决

npm i react-router@latest

Migration guide from v5