reactjs React延迟/挂起+React路由器在获取组件之前不更改路由

zkure5ic  于 2023-03-08  发布在  React
关注(0)|答案(3)|浏览(177)

我正在开发一个应用程序,使用默认的React代码拆分,使用Lazy/Suspense方法和React Router进行组件渲染。目前,当我导航到另一个路径时,如果网速慢,则会更新路径,并在提取组件的同时渲染回退组件,是否可以在当前路径上等待,直到组件包下载完成?

f2uvfpb9

f2uvfpb91#

是的,在并发模式下,useTransition()已启用,您可以创建一个自定义路由器,将history object上的每个navigation methods封装在暂停转换中:

import { useState, unstable_useTransition as useTransition } from 'react';
import { Router } from 'react-router-dom';

const SuspenseRouter = ({ children, history, ...config }) => {
  const [startTransition, isPending] = useTransition(config);
  const [suspenseHistory] = useState(() => {
    const { push, replace, go } = history;

    history.push = (...args) => {
      startTransition(() => { push.apply(history, args); });
    };
    history.replace = (...args) => {
      startTransition(() => { replace.apply(history, args); });
    };
    history.go = (...args) => {
      startTransition(() => { go.apply(history, args); });
    };
  });

  suspenseHistory.isPending = isPending;

  return (
    <Router history={suspenseHistory}>
      {children}
    </Router>
  );
};

export default SuspenseRouter;

示例用法如下所示:

import { Suspense, lazy, unstable_createRoot as createRoot } from 'react';
import { Switch, Route } from 'react-router-dom';
import { createBrowserHistory } from 'history';
import SuspenseRouter from './components/SuspenseRouter';

const history = createBrowserHistory();

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <SuspenseRouter history={history} timeoutMs={2000}>
    <Suspense fallback="Loading...">
      <Switch>
        <Route path="/" exact={true} component={Home} />
        <Route path="/about" component={About} />
      </Switch>
    </Suspense>
  </SuspenseRouter>
);

createRoot(document.getElementById('root')).render(<App />);

如果你想在上一条路线上无限期等待,请将timeoutMs设置为Infinity。在上面的例子中,将其设置为2000应该会在上一条路线上等待最多2秒,然后如果请求的路线的代码还没有下载,则显示fallback

oxiaedzo

oxiaedzo2#

这里是另一个选项:而不是挂起网址更改你可以挂起屏幕更改.
react-router-loading允许在切换屏幕之前显示加载条并获取一些数据。
只需使用此软件包中的SwitchRoute,而不要使用react-router-dom

import { Switch, Route } from "react-router-loading";

添加loading prop 到你想等待的路线:

<Route path="/my-component" component={MyComponent} loading/>

然后,在MyComponent中的获取逻辑的末尾添加loadingContext.done();

import { LoadingContext } from "react-router-loading";
const loadingContext = useContext(LoadingContext);

const loading = async () => {
    //fetching some data

    //call method to indicate that fetching is done and we are ready to switch
    loadingContext.done();
};
wsewodh2

wsewodh23#

对于React路由器v6:
创建挂起路由器:

// SuspenseRouter.tsx

import { useLayoutEffect, useRef, useState, useTransition } from 'react'
import { Router } from 'react-router-dom'
import { BrowserHistory, createBrowserHistory, Update } from 'history'

export interface BrowserRouterProps {
  basename?: string
  children?: React.ReactNode
  window?: Window
}

export function SuspenseRouter({ basename, children, window }: BrowserRouterProps) {
  let historyRef = useRef<BrowserHistory>()
  const [isPending, startTransition] = useTransition()

  if (historyRef.current == null) {
    //const history = createBrowserHistory(startTransition, { window });
    historyRef.current = createBrowserHistory({ window })
  }

  let history = historyRef.current
  let [state, setState] = useState({
    action: history.action,
    location: history.location,
  })

  function setStateAsync(update: Update) {
    startTransition(() => {
      setState(update)
    })
  }

  useLayoutEffect(() => history.listen(setStateAsync), [history])

  return (
    <Router
      basename={basename}
      children={children}
      location={state.location}
      navigationType={state.action}
      navigator={history}
    />
  )
}
export default SuspenseRouter

以及在应用程序tsx中:

// App.tsx

import React, { Suspense, lazy } from 'react';
import { Routes, Route } from 'react-router-dom';
import SuspenseRouter from "./SuspenseRouter";

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <SuspenseRouter window={window}>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  </SuspenseRouter>
);
export default App;
  • 确保您已删除之前使用的路由器
    **这个答案是通过@Jonathan Perlow的评论中的链接给出的。我之所以再次发布它,是因为回应没有答案那么突出,所以没有必要去其他网站。

相关问题