文章目录
初始化项目
create-react-app demo
cd demo
npm i react-router-dom
- 主要相关依赖的版本如下:
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.14.1"
}
}
未使用路由懒加载
根目录\src\index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { Routes, Link, HashRouter as Router, Route } from "react-router-dom";
import Home from "./components/Home";
import User from "./components/User";
function App() {
return (
<>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/user">User</Link>
</li>
</ul>
<Routes>
<Route path="/" exact={true} element={<Home />} />
<Route path="/user" element={<User />} />
</Routes>
</>
);
}
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(
<Router>
<App />
</Router>
);
根目录\src\components\Home.js
import React from "react";
const arr = Array(1000).fill(0);
export default function Home() {
return (
<>
{arr.map((item, index) => (
<p key={index}>我是Home组件---{item}</p>
))}
</>
);
}
根目录\src\components\User.js
import React from "react";
const arr = Array(1000).fill(0);
export default function User() {
return (
<>
{arr.map((item, index) => (
<p key={index}>我是User组件---{item}</p>
))}
</>
);
}
-
对上面的代码存在的问题进行分析:
-
- 我们都知道 React 的脚手架是基于 webpack 来配置的。
- 可能很多小伙伴会觉得很奇怪:我们并没有在目录结构中看到任何 webpack 相关的内容?
- 原因是 React 脚手架将 webpack 相关的配置隐藏起来了,我们可以执行
npm run eject
看到 webpack 的配置信息
-
- 那么项目同样会被 webpack 打包后生成一个 bundle.js 文件。
-
- 而如果通过上面的方式,那么加载首页的时候,Home 组件和 User 组件都会被打包到 bundle.js 中,然后项目启动后就会去请求加载资源(包括 bundle.js),进而渲染页面。
-
- 如果随着我们的路由组件的业务代码越来越复杂,代码量越来越大,那么相应打包后的 bundle.js 文件体积就会越来越大,请求加载资源的速度就会变慢,这就可能会严重影响到页面的首屏加载。
-
- 因此我们可以使用路由懒加载进行优化,即切换到哪个路由然后再去加载该路由对应的组件
-
- 懒加载的本质:直接将组件单独打包成一个分片,然后路由切换的时候去动态的加载这个切片
-
使用路由懒加载优化
根目录\src\utils.js
import React, { Suspense, lazy } from "react";
const loading = () => <div>Loading...</div>;
/**
* 实现路由的分割
* @param {*} loadComponent () => import("./components/Home")
* @returns
*/
export const dynamic = (loadComponent) => {
let LazyComponent = lazy(loadComponent);
return () => (
<Suspense fallback={loading}>
<LazyComponent />
</Suspense>
);
};
根目录\src\index.js
+import { dynamic } from "./utils";
-import Home from "./components/Home";
-import User from "./components/User";
+const LazyHome = dynamic(() => import("./components/Home"));
+const LazyUser = dynamic(() => import("./components/User"));
function App() {
return (
<>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/user">User</Link>
</li>
</ul>
<Routes>
- <Route path="/" exact={true} element={<Home />} />
- <Route path="/user" element={<User />} />
+ <Route path="/" exact={true} element={<LazyHome />} />
+ <Route path="/user" element={<LazyUser />} />
</Routes>
</>
);
}
-
通过上面的代码,我们可以知道的路由懒加载的使用步骤:
-
- 通过
() => import("./components/Home")
的方式拿到原路由组件
- 通过
-
- 将其传给
React.lazy()
, 得到一个新的组件
- 将其传给
-
- 再使用
<Suspense>
组件将新组件
包裹起来
<Suspense>
组件的fallback
属性可接收一个组件,在加载时显示该组件
- 再使用
-
-
使用路由懒加载后:
-
- 我们可以看到当项目启动后
-
- 当切换路由到 User 组件的时候
-
- 并且会发现 bundle.js 文件不再有 Home 组件和 User 组件的代码
-
手写实现路由懒加载
- 即实现 React.lazy()
function lazy(load) {
return class extends React.Component {
state = { Component: null };
componentDidMount() {
// import("./components/Home") 返回的是一个 promise
load().then((result) => {
// console.log(result) // result 其实是一个 webpack 编译后的模块,其 default 属性该模块的组件
this.setState({ Component: result.default });
});
}
render() {
let { Component } = this.state;
return Component && <Component />;
}
};
}