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