今天的夜点心关于 React 的 memo
方法。react
先来看下面的微微微型应用,这个应用从 1 开始数数,每隔 1 秒加 1,并把当前数值的十位数和个位数经过一个名为 Display
的子组件渲染在页面上:git
import React, { Component, PureComponent, useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
class Displayer extends PureComponent {
render() {
const { name, value } = this.props;
console.log(`render ${name} ${value}`);
return (
<div> <label>{name}</label> <span>{value}</span> </div>
)
}
}
const App = () => {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => setCount(prev => prev + 1), 1000);
return () => clearInterval(timer);
}, []);
return (
<div>
<DisplayerFC name="十位" value={Math.floor(count / 10)} />
<DisplayerFC name="个位" value={count % 10} />
</div>
)
}
ReactDOM.render(App, document.getElementById('#app'));
复制代码
上面的代码中,App 组件是应用的根组件;Display 接受一个字符串 name
和一个数字 value
做为属性,每次组件重渲染的时候会在控台打印出这两个属性的值。github
因为使用了 PureComponent
,咱们能够在控台看到用来展现十位的 Display 组件只在数值的十位数变动时进行了渲染,符合预期:数组
如今咱们把 Display 组件重写为一个函数组件:app
const Displayer = ({ name, value }) => {
const { name, value } = this.props;
console.log(`render ${name} ${value}`);
return (
<div> <label>{name}</label> <span>{value}</span> </div>
)
}
复制代码
重启应用,再看控台:dom
此次,用来显示十位数的组件每次都跟着父组件一块儿从新渲染了,跟笔者最初的预期有些不一样。React 的函数组件默认不会根据传入的 props 是否变化选择跳过渲染,以得到对可变数据流的兼容性,这在 Display 组件的计算开销很是大时会带来一些性能问题。更主要的是,看到它作了那么多无畏的渲染,会让做为开发者的咱们心理很不舒服。随着 Hooks 的推广,愈来愈多的组件改用函数组件来实现了,该如何来改善这个性能问题呢?函数
这不,React 从 16.6 开始支持的 memo
函数就能够帮到咱们:性能
import { memo } from 'react';
const MemoizedDislay = memo(Display);
复制代码
只要经过 memo
函数包裹一个现成的组件(类组件或者函数组件均可以),就能够实现相似 PureComponent
的渲染控制效果,减小没必要要的渲染。其实 memo
函数很简单,你能够本身尝试手动实现它,只要记得在比较每一个 prop 是否相等的时候使用 Object.is
。ui
最后,memo
函数支持自定义重渲染规则,你能够经过第二个参数传入一个 compare
函数,告诉 memo
你但愿在什么状况下触发组件的重渲染,compare
函数具备以下的类型结构,入参上次的 props 和当前的 props,出参一个布尔值:this
interface Compare {
(oldProps: Props, newProps: Props): boolean,
}
复制代码
以上就是 React.memo
的相关内容。通常来讲,只要你的应用大体遵循 immutable 的数据流,就基本能够在全部的组件上应用这个函数来改善应用的渲染性能和你的心情。