这是我参与更文挑战的第28天,活动详情查看:更文挑战
打包
官方描述:大多数 React 应用都会使用 Webpack,Rollup 或 Browserify 这类的构建工具来打包文件。打包是一个将文件引入并合并到一个单独文件的过程,最终形成一个 “bundle”。接着在页面上引入该 bundle,整个应用即可一次性加载。
实例:打包前文件和打包后文件对比
- 打包前
// app.js import { add } from './math.js'; console.log(add(16, 26)); // 42 复制代码
// math.js export function add(a, b) { return a + b; } 复制代码
- 打包后
function add(a, b) { return a + b; } console.log(add(16, 26)); // 42 复制代码
代码分割
打包应该注意的问题:
- 随着应用体积的增加,避免因为体积过大而导致加载过慢的问题。
- Webapck等构建工具是支持代码分割的。
- 代码分割能够懒加载用户所需要的内容,能显著的提高应用的性能。
- 尽管没有减少应用整体的代码体积,但是避免了加载用户永远不需要的代码,减少了所需的代码量。
import()
官方描述:引入代码分割的最佳方式是通过动态import语法。
- 使用之前
import { add } from './math'; console.log(add(16, 26)); 复制代码
- 使用之后
import("./math").then(math => { console.log(math.add(16, 26)); }); 复制代码
解读
- 当Webpack解析到该语法的时候,会进行自动的代码分割。
- 如果你是使用的create-react-app等脚手架的情况下,该功能开箱即用。
- 当自己配置Webpack或者Babel的时候,需要根据相关配置文件进行操作。
React.lazy
React.lazy函数能让你像渲染常规这件一样处理动态引入。
- 使用之前
import OtherComponent from './OtherComponent'; 复制代码
- 使用之后
const OtherComponent = React.lazy(() => import('./OtherComponent')); 复制代码
上面的代码将会在组件首次渲染的时候,自动导入包含OtherComponent的组件,React.lazy接收一个函数,这个函数动态调用import并返回一个Promise,该Promise需要resolve一个default export 的组件。然后应在Suspense组件中渲染lazy组件。
import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div> ); } 复制代码
解读
- fallback属性中可以接收任何在组件加载过程中想要展示的React组件。
- 可以将Suspense组件至于懒加载组件之上的任何位置。
- 可以用一个Suspense组件包裹多个懒加载组件。
import React, { Suspense } from 'react'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <section> <OtherComponent /> <AnotherComponent /> </section> </Suspense> </div> ); } 复制代码
异常捕获边界
为什么需要异常捕获边界?
- 因为一旦模块加载失败,会触发一个错误,我们可以通过异常捕获边界技术来处理这些情况,以显示良好的用户体验。
解读
解决这个问题的本质还是通过Supense和React.lazy进行结合。
import React, { Suspense } from 'react'; import MyErrorBoundary from './MyErrorBoundary'; const OtherComponent = React.lazy(() => import('./OtherComponent')); const AnotherComponent = React.lazy(() => import('./AnotherComponent')); const MyComponent = () => ( <div> <MyErrorBoundary> <Suspense fallback={<div>Loading...</div>}> <section> <OtherComponent /> <AnotherComponent /> </section> </Suspense> </MyErrorBoundary> </div> ); 复制代码
基于路由的代码分割
- 如何选择代码分割的位置,需要考虑代码分割不能影响用户的体验。
- 一般选择从路由开始进行分割。
基于路由的分割实例
import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; const Home = lazy(() => import('./routes/Home')); const About = lazy(() => import('./routes/About')); const App = () => ( <Router> <Suspense fallback={<div>Loading...</div>}> <Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> </Switch> </Suspense> </Router> ); 复制代码
命名导出
React.lazy目前只支持默认导出,如果想让其支持命名导出,可以考虑创建一个中间模块。
第一步:分别暴露组件地址
// ManyComponents.js export const MyComponent = /* ... */; export const MyUnusedComponent = /* ... */; 复制代码
第二步:将分别暴露转为默认暴露
// MyComponent.js export { MyComponent as default } from "./ManyComponents.js"; 复制代码
第三步:调用懒加载
// MyApp.js import React, { lazy } from 'react'; const MyComponent = lazy(() => import("./MyComponent.js")); 复制代码