思路拓展:如何打造高性能的 React 应用?
朴素思路:善用 shouldComponentUpdate
React 组件会根据 shouldComponentUpdate 的返回值,来决定是否执行该方法之后的生命周期,进而决定是否对组件进行 re-render(重渲染)默认值是true,也就是无条件更新,我们可以通过对比传入的数据是否发生改变,让组件实现有条件的更新
进阶玩法:PureComponent + Immutable.js
PureComponent:提前帮你安排好更新判定逻辑
每一次实现shouldComponentUpdate比较麻烦,React提供了PureComponent帮我们实现对props和state的对比,但是这种对比是浅对比
- 针对值类型数据对比其值是否相等
- 针对数组、对象等引用类型的数据则对比其引用是否相等
针对PureComponent对于引用类型数据存在的问题,可以通过使用immutable解决,Immutable每一次改变对象,都会重新生成一个新的对象(生成新的引用地址)
**
函数组件的性能优化:React.memo 和 useMemo
React.memo:“函数版”shouldComponentUpdate/PureComponent
React.memo 会帮我们“记住”函数组件的渲染结果,在组件前后两次 props 对比结果一致的情况下,它会直接复用最近一次渲染的结果,这里的 areEqual 函数是一个可选参数,当我们不传入 areEqual 时,React.memo 也可以工作,此时它的作用就类似于 PureComponent——React.memo 会自动为你的组件执行 props 的浅比较逻辑。
import React from "react";
// 定义一个函数组件
function FunctionDemo(props) {
return xxx
}
// areEqual 函数是 memo 的第二个入参,我们之前放在 shouldComponentUpdate 里面的逻辑就可以转移至此处
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
// 使用 React.memo 来包装函数组件
export default React.memo(FunctionDemo, areEqual);
useMemo:更加“精细”的 memo
React.memo 控制是否需要重渲染一个组件,而 useMemo 控制的则是是否需要重复执行某一段逻辑。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
可以把目标逻辑作为第一个参数传入,把逻辑的依赖项数组作为第二个参数传入。这样只有当依赖项数组中的某个依赖发生变化时,useMemo 才会重新执行第一个入参中的目标逻辑。
跟 React 学设计模式:掌握编程“套路”,打造高质量应用
高阶组件(HOC):最经典的组件逻辑复用方式
什么是高阶组件
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。——React 官方
const withProps = (WrappedComponent) => {
const targetComponent = (props) => (
<div className="wrapper-container">
<WrappedComponent {...props} />
</div>
);
return targetComponent;
};
高阶组件是如何实现逻辑复用的?
将公共的业务逻辑抽象到高阶组件中,将业务组件作为高阶组件的函数入参传入,可以避免代码的冗余和重复代码的多次编写 ```javascript // 假设 checkUserAccess 已经在 utils 文件中被封装为了一段独立的逻辑 import checkUserAccess from ‘./utils // 用高阶组件包裹目标组件 const withCheckAccess = (WrappedComponent) => { // 这部分是通用的逻辑:判断用户身份是否合法 const isAccessible = checkUserAccess()
// 将 isAccessible(是否合法) 这个信息传递给目标组件 const targetComponent = (props) => (); return targetComponent; };
const EnhancedAComponent = withCheckAccess(Acomponent);
<a name="zluan"></a>
### Render Props:逻辑复用的另一种思路
> 术语> [“render prop”](https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce)> 是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术。——React 官方> <br />
<a name="ukdPe"></a>
#### 什么是 render props?
高阶组件的使用姿势是用“函数”包裹“组件”,而 render props 恰恰相反,它强调的是用“组件”包裹“函数”
```javascript
import React from 'react'
const RenderChildren = (props) => {
return(
<React.Fragment>
{props.children(props)}
</React.Fragment>
);
};
// 使用
<RenderChildren>
{() => <p>我是 RenderChildren 的子组件</p>}
</RenderChildren>
render props 是如何实现逻辑复用的?
// 假设 checkUserAccess 已经在 utils 文件中被封装为了一段独立的逻辑
import checkUserAccess from './utils
// 定义 render props 组件
const CheckAccess = (props) => {
// 这部分是通用的逻辑:判断用户身份是否合法
const isAccessible = checkUserAccess()
// 将 isAccessible(是否合法) 这个信息传递给目标组件
return <React.Fragment>
{props.children({ ...props, isAccessible })}
</React.Fragment>
};
---------------------------------------------------------------
<CheckAccess>
{
(props) => {
const { isAccessible } = props;
return <ChildComponent {...props} isAccessible={isAccessible} />
}
}
</CheckAccess>