一、代码分割
为什么要使用代码分割:在用webpack进行打包的时候,每个模块被导入合并在一个文件,这个文件叫做 bundle,这些 bundle 在一张页面上包括了整个APP。然而,当 APP 增长的时候,这些 bundle 尺寸开始变得越来越大,因此影响了页面加载时间
使用ant design pro的时候,打包出来的不是一个bundle文件,而是把每个模块打包成了一个async.js。如果用了代码拆分中的import(),就会把对应的js模块单独进行打包,打包出来的js模块名字实例如
56.ffeb4024.async.js
如果不用这个import(),是不会打包出这个模块的
代码拆分简单说就是动态加载组件
// 这里,OtherComponent 是不会请求直到MyComponent开始渲染。但是,因为我们静态导入了 OtherComponent,它会和 MyComponent 一起打包
import OtherComponent from './OtherComponent';
export defautl function MyComponent() {
return (
<div>
<h1>My Component</h1>
<OtherComponent />
</div>
)
}。
1、import()语法进行代码分割
- 这个就是webpack的import()函数(还不是 JavaScript 语言标准的一部分,但是一个期望不久被接受的提案)。import()的语法十分简单。该函数只接受一个参数,就是引用包的地址,这个地址与es6的import以及CommonJS的require语法用到的地址完全一致。返回值为一个promise,在这个promise里面就可以访问对应的包了
- 在代码中所有被import()的模块,都将打成一个单独的包,放在chunk存储的目录下。
- 感觉这个只适用于加载的包只在一个地方使用的情况,因为只有在then的回调里面才可以访问对应的组件,所以不怎么实用。用这个import可以使浏览器运行到这一行代码的时候,才去加载对应的资源
- 在antd design pro的.umi文件夹里面,就已经是用这个代码分割,来定义了路由的了,所以打包出来不是只有单个的chunk
// 下面import在打包的时候,会打包出来多个chunk
import(/* webpackChunkName: "moment" */ 'moment')
.then(({default: moment}) => {
const tommorrow =moment().startOf('day').add(1, 'day');
return tomorrow.format('LLL');
})
// 下面为umi中的使用。实现路由的懒加载
import { routerRedux, dynamic as _dvaDynamic } from 'dva';
const routes = [{
path: '/user',
component: __IS_BROWSER
? _dvaDynamic({
component: () =>
import(/* webpackChunkName: "layouts__UserLayout" */ '../../layouts/UserLayout'), // 这里就使用了import()语法
LoadingComponent: require('F:/demo/ant design pro demo/src/components/PageLoading/index')
.default,
})
: require('../../layouts/UserLayout').default,
}]
2、React.lazy()函数和React.Suspense 组件
这两个东西是配合使用的。
- React.lazy() 函数接收一个函数,函数的返回值必须为一个代表react组件的promise。所以就刚好配合上面的import()一起用了,也可以说是对import()这种动态导入方式的优化
- 被React.lazy()函数包裹的组件,在没有被使用的时候不会被打包进chunk,而是在被调用的时候才被打包
- React.lazy()现在只支持默认导出
<React.Suspense>组件
,这个组件里面包裹的是React.lazy()函数返回的promise组件。一个Suspense可以包裹很多的lazy组件
- fallback属性:这个属性表示,当React.lazy()函数返回的promise组件的状态为pending的时候出现在页面上的占位符,当状态为resolve的时候,这个占位符会消失。
import React, { Suspense, lazy } from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}> // 当里面的组件的状态为pending的时候,页面显示<div>Loading...</div>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}
二、Context
Context:Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。相当于提供了在所有子组件,或者孙子组件都可以获取的一个全局数据
缺点是,用了context之后,会使子组件的可复用性变差
下面说的都是在class组件中使用,如果想在函数组件中使用,则需要使用hook
1、React.createContext()函数
简单说这个函数就是用来创建context的。返回一个Context对象,这个对象里面包含Provider组件和一个Consumer组件。可以给 React.createContext() 传入参数,代表Provider组件的value的默认值,不过没什么必要
2、Provider组件
这个组件是用React.createContext()函数创建的context对象里面的。Provider组件用在父组件中,有一个value属性,代表需要在所有子组件间共享的值。用来包装子组件,被包裹的所有子组件,都可以通过Consumer组件或者contextType属性来获取到Provider组件上面的value属性值
3、Consumer组件
Consumer组件用在子组件中,里面的值为一个函数,函数的参数就是provider里面的value。但是,这个Consumer组件不是很好用,一般不用。
4、使用contextType属性替代Consumer组件
- contextType属性: 这个是在子组件中使用,用来替代Consumer组件,即可以不用Consumer组件来获取Provider组件上面的value值。