1、React.Component() html
用法:git
class A extends React.Component { constructor(props){ super(props) this.state={ } } componentWillMount(){ } render() { return { } } }
源码:github
/** * 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. */ //帮助更新组件状态的基类 function Component(props, context, updater) { this.props = props; //我在工做中没用到context,能够参考下这个: //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" 的话,用另外一个obj赋值 this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. //虽然给updater赋了默认值,但真正的updater是在renderer中注册的 this.updater = updater || ReactNoopUpdateQueue; } //原型上赋了一个flag Component.prototype.isReactComponent = {}; /** 使用setState来改变Component内部的变量 * Sets a subset of the state. Always use this to mutate * state. You should treat `this.state` as immutable. * this.state并非当即更新的,因此在调用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是同步的(它也不是异步的),使用回调获取最新值 * * 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内部变量的API, // 也是开发中很是经常使用且重要的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的更新机制 //在react-dom中实现,不在react中实现 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的深层次改变但未调用setState时,使用该方法 * * 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不调用shouldComponentUpdate方法, * 但会调用componentWillUpdate和componentDidUpdate方法 * * This will not invoke `shouldComponentUpdate`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * * @param {?function} callback Called after update is complete. * @final * @protected */ //强制Component更新一次,不管props/state是否更新 Component.prototype.forceUpdate = function(callback) { this.updater.enqueueForceUpdate(this, callback, 'forceUpdate'); };
解析:
(1)Component()
本质是一个类:dom
class Component { constructor(props, context, updater){ this.props = props this.context = context this.refs = emptyObject this.updater = updater || ReactNoopUpdateQueue } }
(2)setState()
是 Component 原型上的方法,其本质是调用ReactNoopUpdateQueue.js
中的enqueueSetState()
方法,以后的文章会分析enqueueSetState()
的,不要急异步
(3)forceUpdate()
同(2)
ide
(4)我觉得React.Component()
里面实现componentWillMount()
、render()
等内部方法,其实并无。函数
React.Component()
只涉及了props
/context
/refs
/updater
/isReactComponent
/setState
/forceUpdate
,其余均没有本身实现。oop
2、PureComponent优化
什么是 PureComponent:
能够看下这篇文章的第一点:小知识11点(2018.9.4 ) :
复用性强的组件:若是一个组件的渲染只依赖于外界传进去的 props 和本身的 state,而并不依赖于其余的外界的任何数据,也就是说像纯函数同样,给它什么,它就吐出(渲染)什么出来。这种组件的复用性是最强的。即 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的缘由是为了避免直接实例化一个Component实例,能够减小一些内存使用 const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy()); //PureComponent.prototype.constructor = PureComponent pureComponentPrototype.constructor = PureComponent; // Avoid an extra prototype jump for these methods. //避免多一次原型链查找,由于上面两句已经让PureComponent继承了Component //下面多写了一句Object.assign(),是为了不多一次原型链查找 // Object.assign是浅拷贝, // 将Component.prototype上的方法都复制到PureComponent.prototype上 // 也就是pureComponent的原型上 // 详细请参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign Object.assign(pureComponentPrototype, Component.prototype); // 惟一的区别就是在原型上添加了isPureReactComponent属性去表示该Component是PureComponent pureComponentPrototype.isPureReactComponent = true; export {Component, PureComponent};
解析:
(1)重点看最后三行作了什么:(减小内存消耗,减小原型链查找次数)
① const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy())
新建了空方法ComponentDummy
,并继承Component
的原型;PureComponent.prototype
等于ComponentDummy
的实例
这样作的目的是:
若是让PureComponent.prototype
直接等于Component
的实例对象的话(继承原型),会多继承Component
的constructor
,可是PureComponent
已经有本身的constructor
了,这样就会多消耗一些内存。
因此会新建ComponentDummy
,只继承Component
的原型,不包括constructor
,以此来节省内存。
② 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
中都有,无需再从__proto__
上查找了。
(2)pureComponentPrototype.isPureReactComponent = true
在ReactFiberClassComponent.js
中,有对isPureReactComponent
的判断:
if (ctor.prototype && ctor.prototype.isPureReactComponent) { return ( !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) ); }
注意:(重要)
(1)整个React
中判断 Component
类 是否须要更新,只有两个地方:
一 是看有没有shouldComponentUpdate
方法
二 就是ReactFiberClassComponent.js
中的checkShouldComponentUpdate()
中对PureComponent
的判断
(2)PureComponent
与Component
惟一的区别:PureComponent
是自带了一个简单的shouldComponentUpdate
来优化更新机制的。
(完)