摘要:自身的源碼也很簡單,節(jié)選如下上面的就是暴露給外部使用的。關(guān)于的源碼分析就到這里。這是內(nèi)部使用的一個工具集。不過也不是萬能的,特定情況下自己實(shí)現(xiàn)可能更高效。
TL;DR
React 15.3.0 新增了一個 PureComponent 類,以 ES2015 class 的方式方便地定義純組件 (pure component)。這篇文章分析了一下源碼實(shí)現(xiàn),并衍生探討了下 shallowCompare 和 PureRenderMixin。相關(guān)的 GitHub PR 在 這里 。
PureComponent 源碼分析這個類的用法很簡單,如果你有些組件是純組件,那么把繼承類從 Component 換成 PureComponent 即可。當(dāng)組件更新時,如果組件的 props 和 state 都沒發(fā)生改變,render 方法就不會觸發(fā),省去 Virtual DOM 的生成和比對過程,達(dá)到提升性能的目的。
import React, { PureComponent } from "react" class Example extends PureComponent { render() { // ... } }
PureComponent 自身的源碼也很簡單,節(jié)選如下:
function ReactPureComponent(props, context, updater) { // Duplicated from ReactComponent. this.props = props; this.context = context; this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. this.updater = updater || ReactNoopUpdateQueue; } function ComponentDummy() {} ComponentDummy.prototype = ReactComponent.prototype; ReactPureComponent.prototype = new ComponentDummy(); ReactPureComponent.prototype.constructor = ReactPureComponent; // Avoid an extra prototype jump for these methods. Object.assign(ReactPureComponent.prototype, ReactComponent.prototype); ReactPureComponent.prototype.isPureReactComponent = true;
上面的 ReactPureComponent 就是暴露給外部使用的 PureComponent 。可以看到它只是繼承了 ReactComponent 再設(shè)定了一下 isPureReactComponent 屬性。ComponentDummy 是典型的 JavaScript 原型模擬繼承的做法,對此有疑惑的可以看 我的另一篇文章 。另外,為了避免原型鏈拉長導(dǎo)致方法查找的性能開銷,還用 Object.assign 把方法從 ReactComponent 拷貝過來了。
跟 PureRenderMixin 不一樣的是,這里完全沒有實(shí)現(xiàn) shouldComponentUpdate。那 PureComponent 的 props/state 比對是在哪里做的呢?答案是 ReactCompositeComponent。
ReactCompositeComponent 這個類的信息太少,我只能推測它是負(fù)責(zé)實(shí)際渲染并維護(hù)組件實(shí)例的對象。建議大家從高層次了解 React 對組件的更新機(jī)制即可。以下幾篇官方文檔看完就足夠了。
Advanced Performance
Reconciliation
React (Virtual) DOM Terminology
這個類的代碼改動很多,但關(guān)鍵就在 這里 。下面是我簡化后的代碼片段:
// 定義 CompositeTypes var CompositeTypes = { ImpureClass: 0, // 繼承自 Component 的組件 PureClass: 1, // 繼承自 PureComponent 的組件 StatelessFunctional: 2, // 函數(shù)組件 }; // 省略一堆代碼,因?yàn)榧尤肓?CompositeTypes 造成的調(diào)整 // 這個變量用來控制組件是否需要更新 var shouldUpdate = true; // inst 是組件實(shí)例 if (inst.shouldComponentUpdate) { shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext); } else { if (this._compositeType === CompositeType.PureClass) { // 用 shallowEqual 對比 props 和 state 的改動 // 如果都沒改變就不用更新 shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState); } }
簡而言之,ReactCompositeComponent 會在 mount 的時候判斷各個組件的類型,設(shè)定 _compositeType ,然后根據(jù)這個類型來判斷是非需要更新組件。這個 PR 中大部分改動都是 因?yàn)榧恿?CompositeTypes 而做的調(diào)整性工作,實(shí)際跟 PureComponent 有關(guān)的就是 shallowEqual 的那兩行。
關(guān)于 PureComponent 的源碼分析就到這里。其他的就都是細(xì)節(jié)和測試,有興趣的可以自己看看 PR 。
shallowEqual, shallowCompare, PureRenderMixin 的聯(lián)系我們知道在 PureComponent 出現(xiàn)之前,shallowCompare 和 PureRenderMixin 都可以做一樣的事情。于是好奇看了一下后兩者的代碼。
shallowCompare 的源碼:
var shallowEqual = require("shallowEqual"); function shallowCompare(instance, nextProps, nextState) { return ( !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState) ); } module.exports = shallowCompare;
PureRenderMixin 的源碼:
var shallowCompare = require("shallowCompare"); var ReactComponentWithPureRenderMixin = { shouldComponentUpdate: function(nextProps, nextState) { return shallowCompare(this, nextProps, nextState); }, }; module.exports = ReactComponentWithPureRenderMixin;
可以看到,shallowCompare 依賴 shallowEqual ,做的是跟剛才在 ReactCompositeComponent 里一樣的事情 -- 對比 props 和 state 。這個工具函數(shù)一般配合組件的 shouldComponentUpdate 一起使用,而這就是 PureRenderMixin 做的事情。不過 PureRenderMixin 是配合 React.createClass 這種老的組件定義方式使用的,在 ES2015 class 里用起來不是很方便,這也是 PureComponent 誕生的原因之一。
最后 shallowEqual 這玩意定義在哪里呢?它其實(shí)不是 React 的一部分,而是 fbjs 的一部分。這是 Facebook 內(nèi)部使用的一個工具集。
小結(jié)React 之前一直沒有針對 ES2015 class 的純組件寫法,雖然自己實(shí)現(xiàn)起來并不麻煩,但這也算給出了一個官方的解決方案,可以不再依賴 addon 了。不過 PureComponent 也不是萬能的,特定情況下自己實(shí)現(xiàn) shouldComponentUpdate 可能更高效。
參考資料PureComponent PR
shallowEqual
Shallow Compare
PureRenderMixin
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/80199.html
摘要:首先是創(chuàng)建了一個構(gòu)造函數(shù),他的原型指到的原型然后創(chuàng)建了一個加上了和一樣的屬性這里為啥不用。的原型指向的實(shí)例修改原型的屬性使其正確指向的構(gòu)造函數(shù),并掛一個的屬性。 每次都信誓旦旦的給自己立下要好好學(xué)習(xí)react源碼的flag,結(jié)果都是因?yàn)槟硞€地方卡住了,或是其他原因沒看多少就放棄了。這次又給自己立個flag-堅(jiān)持看完react源碼。為了敦促自己,特開設(shè)這樣一個專欄來記錄自己的學(xué)習(xí)歷程,這...
摘要:只涉及了,其他均沒有自己實(shí)現(xiàn)。這種組件的復(fù)用性是最強(qiáng)的。所以會新建,只繼承的原型,不包括,以此來節(jié)省內(nèi)存。 showImg(https://segmentfault.com/img/remote/1460000019783989); 一、React.Component() GitHub:https://github.com/AttackXiaoJinJin/reactExplain/...
摘要:本次分析的源碼采用的是的版本核心接口提供了處理的工具集我們先來看看做了什么事情即當(dāng)為空時,返回不為時調(diào)用,最終返回一個數(shù)組這里說一下,可以通過傳入的對所有子組件進(jìn)行操作,具體使用方法看下圖參數(shù)通過配合的例子把父組件的賦值給每個子組件我們先不 本次分析的源碼采用的是16.4.1的版本 核心接口 showImg(https://segmentfault.com/img/bVbeT9f?w=...
摘要:往往純的單頁面應(yīng)用一般不會太復(fù)雜,所以這里不引入和等等,在后面復(fù)雜的跨平臺應(yīng)用中我會將那些技術(shù)一擁而上。構(gòu)建極度復(fù)雜,超大數(shù)據(jù)的應(yīng)用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React為了大型應(yīng)用而生,Electron和React-native賦予了它構(gòu)建移動端跨平臺App和桌面應(yīng)用的能力,Taro則賦...
摘要:往往純的單頁面應(yīng)用一般不會太復(fù)雜,所以這里不引入和等等,在后面復(fù)雜的跨平臺應(yīng)用中我會將那些技術(shù)一擁而上。構(gòu)建極度復(fù)雜,超大數(shù)據(jù)的應(yīng)用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React為了大型應(yīng)用而生,Electron和React-native賦予了它構(gòu)建移動端跨平臺App和桌面應(yīng)用的能力,Taro則賦...
閱讀 1441·2021-09-03 10:29
閱讀 3465·2019-08-29 16:24
閱讀 2028·2019-08-29 11:03
閱讀 1419·2019-08-26 13:52
閱讀 2932·2019-08-26 11:36
閱讀 2796·2019-08-23 17:19
閱讀 567·2019-08-23 17:14
閱讀 816·2019-08-23 13:59