摘要:只涉及了,其他均沒有自己實(shí)現(xiàn)。這種組件的復(fù)用性是最強(qiáng)的。所以會(huì)新建,只繼承的原型,不包括,以此來節(jié)省內(nèi)存。
一、React.Component()
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactBaseClasses.js
用法:
class A extends React.Component { constructor(props){ super(props) this.state={ } } componentWillMount(){ } render() { return { } } }
源碼:
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import invariant from "shared/invariant"; import lowPriorityWarning from "shared/lowPriorityWarning"; import ReactNoopUpdateQueue from "./ReactNoopUpdateQueue"; const emptyObject = {}; if (__DEV__) { Object.freeze(emptyObject); } /** * Base class helpers for the updating state of a component. */ //幫助更新組件狀態(tài)的基類 function Component(props, context, updater) { this.props = props; //我在工作中沒用到context,可以參考下這個(gè): //https://www.cnblogs.com/mengff/p/9511419.html //是React封裝的全局變量API this.context = context; // If a component has string refs, we will assign a different object later. //如果在組件中用了 ref="stringa" 的話,用另一個(gè)obj賦值 this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. //雖然給updater賦了默認(rèn)值,但真正的updater是在renderer中注冊(cè)的 this.updater = updater || ReactNoopUpdateQueue; } //原型上賦了一個(gè)flag Component.prototype.isReactComponent = {}; /** 使用setState來改變Component內(nèi)部的變量 * Sets a subset of the state. Always use this to mutate * state. You should treat `this.state` as immutable. * this.state并不是立即更新的,所以在調(diào)用this.setState后可能 不能 拿到新值 * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * * 不能保證this.state是同步的(它也不是異步的),使用回調(diào)獲取最新值 * * There is no guarantee that calls to `setState` will run synchronously, * as they may eventually be batched together. You can provide an optional * callback that will be executed when the call to setState is actually * completed. * * When a function is provided to setState, it will be called at some point in * the future (not synchronously). It will be called with the up to date * component arguments (state, props, context). These values can be different * from this.* because your function may be called after receiveProps but before * shouldComponentUpdate, and this new state, props, and context will not yet be * assigned to this. * * @param {object|function} partialState Next partial state or function to * produce next partial state to be merged with current state. * @param {?function} callback Called after state is updated. * @final * @protected */ // 更新Component內(nèi)部變量的API, // 也是開發(fā)中非常常用且重要的API // https://www.jianshu.com/p/7ab07f8c954c // https://www.jianshu.com/p/c19e259870a5 //partialState:要更新的state,可以是Object/Function //callback: setState({xxx},callback) Component.prototype.setState = function(partialState, callback) { // 判斷setState中的partialState是否符合條件, // 如果不符合則拋出Error invariant( typeof partialState === "object" || typeof partialState === "function" || partialState == null, "setState(...): takes an object of state variables to update or a " + "function which returns an object of state variables.", ); //重要!state的更新機(jī)制 //在react-dom中實(shí)現(xiàn),不在react中實(shí)現(xiàn) this.updater.enqueueSetState(this, partialState, callback, "setState"); }; /** * Forces an update. This should only be invoked when it is known with * certainty that we are **not** in a DOM transaction. * * 在Component的深層次改變但未調(diào)用setState時(shí),使用該方法 * * You may want to call this when you know that some deeper aspect of the * component"s state has changed but `setState` was not called. * * forceUpdate不調(diào)用shouldComponentUpdate方法, * 但會(huì)調(diào)用componentWillUpdate和componentDidUpdate方法 * * This will not invoke `shouldComponentUpdate`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * * @param {?function} callback Called after update is complete. * @final * @protected */ //強(qiáng)制Component更新一次,無論props/state是否更新 Component.prototype.forceUpdate = function(callback) { this.updater.enqueueForceUpdate(this, callback, "forceUpdate"); };
解析:
(1)Component()本質(zhì)是一個(gè)類:
class Component { constructor(props, context, updater){ this.props = props this.context = context this.refs = emptyObject this.updater = updater || ReactNoopUpdateQueue } }
(2)setState()是 Component 原型上的方法,其本質(zhì)是調(diào)用ReactNoopUpdateQueue.js中的enqueueSetState()方法,之后的文章會(huì)分析enqueueSetState()的,不要急
(3)forceUpdate()同(2)
(4)我以為React.Component()里面實(shí)現(xiàn)componentWillMount()、render()等內(nèi)部方法,其實(shí)并沒有。
React.Component()只涉及了props /context /refs /updater /isReactComponent /setState /forceUpdate ,其他均沒有自己實(shí)現(xiàn)。
二、PureComponent
GitHub:
https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactBaseClasses.js
什么是 PureComponent:
可以看下這篇文章的第一點(diǎn):小知識(shí)11點(diǎn)(2018.9.4 ) :
復(fù)用性強(qiáng)的組件:如果一個(gè)組件的渲染只依賴于外界傳進(jìn)去的 props 和自己的 state,而并不依賴于其他的外界的任何數(shù)據(jù),也就是說像純函數(shù)一樣,給它什么,它就吐出(渲染)什么出來。這種組件的復(fù)用性是最強(qiáng)的。即 Pure Component 或稱 Dumb Component。
用法:
class A extends React.PureComponent { //同React.Component() }
源碼:
function ComponentDummy() {} //ComponentDummy的原型 繼承 Component的原型 ComponentDummy.prototype = Component.prototype; /** * Convenience component with default shallow equality check for sCU. */ function PureComponent(props, context, updater) { this.props = props; this.context = context; // If a component has string refs, we will assign a different object later. this.refs = emptyObject; this.updater = updater || ReactNoopUpdateQueue; } //PureComponent是繼承自Component的,下面三行就是在繼承Component //將Component的方法拷貝到pureComponentPrototype上 // 用ComponentDummy的原因是為了不直接實(shí)例化一個(gè)Component實(shí)例,可以減少一些內(nèi)存使用 const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()); //PureComponent.prototype.constructor = PureComponent pureComponentPrototype.constructor = PureComponent; // Avoid an extra prototype jump for these methods. //避免多一次原型鏈查找,因?yàn)樯厦鎯删湟呀?jīng)讓PureComponent繼承了Component //下面多寫了一句Object.assign(),是為了避免多一次原型鏈查找 // Object.assign是淺拷貝, // 將Component.prototype上的方法都復(fù)制到PureComponent.prototype上 // 也就是pureComponent的原型上 // 詳細(xì)請(qǐng)參考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign Object.assign(pureComponentPrototype, Component.prototype); // 唯一的區(qū)別就是在原型上添加了isPureReactComponent屬性去表示該Component是PureComponent pureComponentPrototype.isPureReactComponent = true; export {Component, PureComponent};
解析:
(1)重點(diǎn)看最后三行做了什么:(減少內(nèi)存消耗,減少原型鏈查找次數(shù))
① const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy())
新建了空方法ComponentDummy ,并繼承Component的原型;
PureComponent.prototype等于ComponentDummy的實(shí)例
這樣做的目的是:
如果讓PureComponent.prototype直接等于Component的實(shí)例對(duì)象的話(繼承原型),會(huì)多繼承Component的constructor,但是PureComponent已經(jīng)有自己的constructor了,這樣就會(huì)多消耗一些內(nèi)存。
所以會(huì)新建ComponentDummy,只繼承Component的原型,不包括constructor,以此來節(jié)省內(nèi)存。
② pureComponentPrototype.constructor = PureComponent
原型的constructor等于自身,覆蓋掉Component.prototype的constructor(Component)
①、② 就是讓PureComponent繼承Component,那么為什么還要多寫一句Object.assign(pureComponentPrototype, Component.prototype)呢?
③ PureComponent的prototype淺拷貝Component的prototype的所有屬性
不寫 ③ 的話:
pureComponentPrototype.__proto__=== ComponentDummy.prototype //true //也就是 PureComponent.prototype.__proto__=== Component.prototype //true
這樣就多了一層隱式原型的查找,為了減少一次原型鏈查找,所以寫了
Object.assign(pureComponentPrototype, Component.prototype)
這樣的話:
Component.prototype中的方法在PureComponent.prototype中都有,無需再?gòu)?b>__proto__上查找了。
(2)pureComponentPrototype.isPureReactComponent = true
在ReactFiberClassComponent.js中,有對(duì)isPureReactComponent的判斷:
if (ctor.prototype && ctor.prototype.isPureReactComponent) { return ( !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) ); }
注意:(重要)
(1)整個(gè)React中判斷 Component類 是否需要更新,只有兩個(gè)地方:
一 是看有沒有shouldComponentUpdate方法
二 就是ReactFiberClassComponent.js中的checkShouldComponentUpdate()中對(duì)PureComponent的判斷
(2)PureComponent與Component唯一的區(qū)別:
PureComponent是自帶了一個(gè)簡(jiǎn)單的shouldComponentUpdate來優(yōu)化更新機(jī)制的。
(完)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105711.html
摘要:本次分析的源碼采用的是的版本核心接口提供了處理的工具集我們先來看看做了什么事情即當(dāng)為空時(shí),返回不為時(shí)調(diào)用,最終返回一個(gè)數(shù)組這里說一下,可以通過傳入的對(duì)所有子組件進(jìn)行操作,具體使用方法看下圖參數(shù)通過配合的例子把父組件的賦值給每個(gè)子組件我們先不 本次分析的源碼采用的是16.4.1的版本 核心接口 showImg(https://segmentfault.com/img/bVbeT9f?w=...
摘要:在前端開發(fā)過程中,源碼解讀是必不可少的一個(gè)環(huán)節(jié),我們直接進(jìn)入主題,注意當(dāng)前版本號(hào)。注意包文件僅僅是的必要的功能性的定義,它必須要結(jié)合一起使用下是,原生環(huán)境下是。 在前端開發(fā)過程中,源碼解讀是必不可少的一個(gè)環(huán)節(jié),我們直接進(jìn)入主題,注意當(dāng)前 React 版本號(hào) 16.8.6。 注意:react 包文件僅僅是 React components 的必要的、功能性的定義,它必須要結(jié)合 React...
摘要:一作用獲取目標(biāo)的實(shí)例使用源碼可修改的不可變的對(duì)象沒見過這種寫法初始化對(duì)象,屬性初始值為解析源碼比較簡(jiǎn)單,就是返回了帶有屬性的二作用從父組件中獲取子組件是的實(shí)例使用是沒有實(shí)例的,因?yàn)樗牵詻]有,所以不能通過來拿到實(shí)例將的傳給子組件,并綁定 showImg(https://segmentfault.com/img/remote/1460000019877636); 一、React.cr...
摘要:用這種方式創(chuàng)建組件時(shí),并沒有對(duì)內(nèi)部的函數(shù),進(jìn)行綁定,所以如果你想讓函數(shù)在回調(diào)中保持正確的,就要手動(dòng)對(duì)需要的函數(shù)進(jìn)行綁定,如上面的,在構(gòu)造函數(shù)中對(duì)進(jìn)行了綁定。 當(dāng)我們談起React的時(shí)候,多半會(huì)將注意力集中在組件之上,思考如何將頁面劃分成一個(gè)個(gè)組件,以及如何編寫可復(fù)用的組件。但對(duì)于接觸React不久,還沒有真正用它做一個(gè)完整項(xiàng)目的人來說,理解如何創(chuàng)建一個(gè)組件也并不那么簡(jiǎn)單。在最開始的時(shí)候...
摘要:往往純的單頁面應(yīng)用一般不會(huì)太復(fù)雜,所以這里不引入和等等,在后面復(fù)雜的跨平臺(tái)應(yīng)用中我會(huì)將那些技術(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)建移動(dòng)端跨平臺(tái)App和桌面應(yīng)用的能力,Taro則賦...
閱讀 943·2021-11-25 09:43
閱讀 1323·2021-11-17 09:33
閱讀 3046·2019-08-30 15:44
閱讀 3337·2019-08-29 17:16
閱讀 505·2019-08-28 18:20
閱讀 1680·2019-08-26 13:54
閱讀 581·2019-08-26 12:14
閱讀 2198·2019-08-26 12:14