You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router/lazy Suspense+useTransition 下页渲染前停留当前页

React Router v5 + React 18 无闪烁懒加载路由实现方案

问题核心

使用React.lazy+React.Suspense实现路由懒加载时,默认配置下路由跳转是紧急更新,会立刻卸载旧页面、显示Suspense fallback,等新页面资源加载完再替换成新页面,必然出现加载闪烁。
要实现的效果:跳转时保留当前已渲染页面,等新页面资源加载、渲染完成后再一次性完成路由切换,完全消除闪烁。
运行环境要求:react v18.2、react-router v5

实现代码

核心思路是利用React 18的useTransition将路由状态更新标记为非紧急过渡更新,过渡期间保留旧UI,直到新页面就绪再替换。

import React, { useState, useTransition, Suspense, lazy, useEffect } from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { createBrowserHistory } from 'history';

// 初始化独立history实例
const customHistory = createBrowserHistory();

// 路由懒加载声明
const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const UserCenter = lazy(() => import('./pages/UserCenter'));

function App() {
  const [isPending, startTransition] = useTransition();
  // 自主托管路由location状态
  const [routerLocation, setRouterLocation] = useState(customHistory.location);

  useEffect(() => {
    // 监听路由变化,将location更新包裹在startTransition中标记为过渡更新
    const unListen = customHistory.listen((updateConfig) => {
      startTransition(() => {
        setRouterLocation(updateConfig.location);
      });
    });
    return unListen;
  }, [startTransition]);

  return (
    <Router history={customHistory}>
      {/* 关键:Suspense fallback设为null,避免过渡期间替换旧页面显示整块加载态 */}
      <Suspense fallback={null}>
        {/* 传入自主托管的location给Switch,接管路由渲染判断 */}
        <Switch location={routerLocation}>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
          <Route path="/user" component={UserCenter} />
        </Switch>
      </Suspense>
      {/* 可选:非侵入式加载提示,不占用页面布局位置,不会造成内容闪烁 */}
      {isPending && (
        <div className="fixed top-0 left-0 h-[2px] w-full bg-blue-500 animate-[loading_1s_ease-in-out_infinite]" />
      )}
    </Router>
  );
}

export default App;

关键注意点

  • 包裹路由的Suspense不能设置整块页面级的fallback,否则会直接覆盖旧页面触发闪烁,fallback设为null即可让React在过渡期间保留旧页面
  • React Router v5没有内置React 18过渡特性支持,必须自主托管location状态,把路由更新逻辑放到startTransition回调中,才能让React识别这是可中断的过渡更新
  • 不需要修改原有Link组件、编程式导航(history.push/history.replace)的写法,根层的history监听会自动接管所有路由跳转逻辑
  • 加载提示建议用顶部细进度条、角落小loading标识这类不替换主内容的形式,避免破坏页面连续性

旧方案失效原因

网上流传的早期方案大多是React 18正式版发布前的实现,当时useTransitionAPI行为未稳定,也没有接管React Router内部的location更新逻辑,路由跳转依然属于紧急更新,会立刻卸载旧页面触发fallback,无法解决闪烁问题。

内容的提问来源于stack exchange,提问作者bearsworth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:24:30