博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React源码解析(三):react-component
阅读量:5743 次
发布时间:2019-06-18

本文共 6945 字,大约阅读时间需要 23 分钟。

在我们平时写一个类组件的时候,一般都会继承一个React.Component这个基类,我们可能会觉得,这个baseClass可能封装各种各样的功能(钩子函数等等),它帮助我们运行render函数,然后最终不是我们写在里面的dom标签、子组件之类的把它们都渲染到浏览器里的这种形式。但实际是这样的吗?答案是否定的。

在react当中不止有Component这一个baseClass, 它还有一个PureComponent这个baseClass, 它们俩唯一的区别就是PureComponent提供了一个shouldComponentUpdate简单的实现,在props没有变化的情况下减少不必要的更新。

我们先看看这个Component和PureComponent的实现源码:

/** * 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;      this.context = context;      // If a component has string refs, we will assign a different object later.      this.refs = emptyObject;      // We initialize the default updater but the real one gets injected by the      // renderer.      this.updater = updater || ReactNoopUpdateQueue;}Component.prototype.isReactComponent = {};/** * Sets a subset of the state. Always use this to mutate * state. You should treat `this.state` as immutable. * * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * * 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.prototype.setState = function(partialState, callback) {      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.',      );      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. * * 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. * * This will not invoke `shouldComponentUpdate`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * * @param {?function} callback Called after update is complete. * @final * @protected */Component.prototype.forceUpdate = function(callback) {      this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');};/** * Deprecated APIs. These APIs used to exist on classic React classes but since * we would like to deprecate them, we're not going to move them over to this * modern base class. Instead, we define a getter that warns if it's accessed. */if (__DEV__) {      const deprecatedAPIs = {            isMounted: [            'isMounted',            'Instead, make sure to clean up subscriptions and pending requests in ' +            'componentWillUnmount to prevent memory leaks.',            ],            replaceState: [                  'replaceState',                  'Refactor your code to use setState instead (see ' +                    'https://github.com/facebook/react/issues/3236).',            ],      };      const defineDeprecationWarning = function(methodName, info) {            Object.defineProperty(Component.prototype, methodName, {                  get: function() {                        lowPriorityWarning(                              false,                              '%s(...) is deprecated in plain JavaScript React classes. %s',                              info[0],                              info[1],                        );                        return undefined;                  },            });      };      for (const fnName in deprecatedAPIs) {            if (deprecatedAPIs.hasOwnProperty(fnName)) {                  defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);            }      }}function ComponentDummy() {}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;}const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());pureComponentPrototype.constructor = PureComponent;// Avoid an extra prototype jump for these methods.Object.assign(pureComponentPrototype, Component.prototype);pureComponentPrototype.isPureReactComponent = true;export {Component, PureComponent};复制代码

我们可以看到Component是一个函数,是一个使用函数进行的类声明的一个方式。它接受三个参数props,context,updater,props和context在使用中大家都知道了,那么这个updater什么呢?我们往下看。

我们看到Component原型上挂在了一个方法setState,这个使我们在使用react时最常用的api了,是用来更新我们组件的状态的。它接受两个参数partial和callback,partial可以是一个对象或者一个方法,在后面的版本都推荐使用方法,callback就是在我们这个state更新完之后它会执行callback。

我们可以看到在这个setState方法里,前半部分都是一个提醒,来判断partial这个是否符合预期要求,如果不符合就给出一个错误的提示。重要的是最后这一行代码this.updater.enqueueSetState(this, partialState, callback, 'setState') 其实我们在调用setState方法时,在Component这个对象里面它什么都没有做,它只是调用了Component初始化时传入的updater对象下的enqueueSetState这个方法。enqueueSetState这个方法我们先不讲,它是在react-dom里面实现的,跟react的代码是没有任何关系的。为什么要这么去做呢,因为不用的平台react-native和react-dom它们用的核心是一样的,也就是它们Component的api是一模一样的。但是具体的我们更新state走的流程就是这个具体的渲染的流程是跟平台有关的。react-dom平台和react-native平台它们的实现方式是不一样的,所以这一部分它作为一个参数让不同的平台去传入进来,去定制它的一个实现方法。所以,这就是为什么要使用一个对象传入进来之后在setState里面去调用的原因。具体的实现会在后面的文章中讲道。

加下去我们还会看到Component上还有一个方法叫forceUpdate, 它内部也是调用了this.updater.enqueueSetState(this, callback, 'forceUpdate')这个方法。这个api我们不常用,它的作用就是强制我们Component去更新一遍,即便我们的state没有更新。

然后再往下就是两个即将废弃的api,isMounted 和 replaceState。

至此就是Component定义的全部的内容,没有任何关于生命周期的一些方法,是不是和你想的不一样。

接下来我们来看一下另一个baseClass,它就是PureComponent。我们可以认为它是继承Component,它们接受的东西都是一样的。唯一的区别就是它在PureComponent上加了一个isPureReactComponent, 通过这么一个属性来标识继承自这个类的组件是一个PureComponent。然后在后续的更新当中,react-dom它会主动的去判断它是不是一个PureComponent, 然后根据props是否更新来判断这个组件是否更新。

以上就是对Component和PureComponent全部的分析。

转载地址:http://fxszx.baihongyu.com/

你可能感兴趣的文章
Visifire charts ToolBar
查看>>
Mysql查询
查看>>
数据传输流程和socket简单操作
查看>>
ProbS CF matlab源代码(二分系统)(原创作品,转载注明出处,谢谢!)
查看>>
OC中KVC的注意点
查看>>
JQ入门(至回调函数)
查看>>
【洛天依】几首歌的翻唱(无伴奏)
查看>>
OpenSSL初瞻及本系列的博文的缘由
查看>>
ISO8583接口的详细资料
查看>>
tmux不自动加载配置文件.tmux.conf
查看>>
[MOSEK] Stupid things when using mosek
查看>>
程序实例---栈的顺序实现和链式实现
查看>>
服务的使用
查看>>
Oracle 用户与模式
查看>>
MairDB 初始数据库与表 (二)
查看>>
拥在怀里
查看>>
chm文件打开,有目录无内容
查看>>
whereis、find、which、locate的区别
查看>>
一点不懂到小白的linux系统运维经历分享
查看>>
桌面支持--打不开网页上的pdf附件解决办法(ie-tools-compatibility)
查看>>