今天的夜點心關於 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 的數據流,就基本能夠在全部的組件上應用這個函數來改善應用的渲染性能和你的心情。