React16源码: Component与PureComponent源码实现

React组件类型解析:Component、PureComponent与函数组件 React组件是构建用户界面的核心单元,主要分为类组件和函数组件两种范式。类组件通过继承React.Component或React.PureComponent实现,提供了完整的生命周期管理和状态控制能力,其中PureComponent通过浅比较props和state自动优化渲染性能。函数组件则是更轻量的选择,配合Hooks可以实现与类组件相同的功能,且代码更简洁。在React Fiber架构下,函数组件通过闭包管理状态,避免了类组件中this绑定的问题。对于性能敏感的场景,PureComponent的浅比较 阅读详情

概述

  • Component 就是组件, 这个概念依托于最直观的在react上的一个表现,那就是 React.Component
  • 我们写的组件大都是继承于 React.Component 这个baseClass 而写的类
  • 这个类代表着我们使用 react 去实现的一个组件
  • 那么在react当中不仅仅只有 Component 这一个baseClass,还有另外一个叫 PureComponent
  • PureComponent 跟 Component 唯一区别
    • 提供了简便的 shouldComponentUpdate 的一个实现
    • 保证组件在 props 没有任何变化的情况下减少不必要的更新

源码分析

1 ) API 位置定位

  • 在入口文件 React.js里面,可看到
    import {Component, PureComponent} from './ReactBaseClasses';
    
  • 之后,我们定位到 ReactBaseClasses.js 里面

ReactBaseClasses.js 源码

/**
 * 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};

2 )源码分析

2.1 Component

  • 从上面看到,Component 是一个function,它是一个使用function去进行类的声明的一个方式

  • 它接收三个参数,一个是 props,一个是 context,还有一个是 updater

  • 关于 props 和 context 可以发现, 在这里面进行赋值

    • this.props = props
    • this.context = context
    • 就是我们在组件内部去使用的时候,可以直接去用
  • 然后再声明了一个 refs,它是一个 emptyObject

    • 参考 stringRef, 最终会把获取的节点的实例挂载在 this.refs 上面
    • 就是我们 stringRef 使用的 key 挂载在上面
  • 关于 updater 出场率并不高,先跳过

  • 往下看,找到 Component.prototype.setState

    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');
    };
    
    • 这个就是我们使用的最多的一个API, 它是用来更新我们组件的状态
    • 它接收的两个参数
      • 一个是 partialState, 就是我们要更新的一个新的state,可以是一个对象,也可以是一个方法
      • 第二个是 callback, 那么callback就是在我们state真正的更新完之后才会执行这个callback
    • 这个方法里面第一段代码是一个提醒
      • 就是它判断我们的对象是不是object或者是function, 或者是不等于null
      • 如果都不满足,它就会给出一个错误提醒, 这个其实不太重要
    • 下面一段才是重点 this.updater.enqueueSetState
      • 调用 setState,其实在 Component 对象里面, 什么事情都没有做
      • 它只是调用了初始化Component时, 传入的这个update对象上面的一个 enqueueSetState 方法
      • 这个方法是在 react-dom 里面去实现的,跟react的代码是没有任何关系的
      • 这样做的原因是,不同的平台,比如说 react-dom 和 react-native
      • 它们用的 react 的核心是一模一样的,也就是说,Component 这个API是一模一样的
      • 但是,具体的涉及到更新state之后如何进行渲染,而这个渲染的流程在跟平台有关的
      • 所以这里是一种类似于依赖注入的策略模式,这是一种策略模式的应用
      • 不同的环境(例如浏览器环境与 React Native 环境)可以提供不同的 updater 实现,以适应各自平台的特性来进行状态更新
      • 客户端可以根据需要选择不同的策略,以满足不同的需求或适应不同的环境
      • react-dom平台跟 react-native 平台,它们的实现渲染的方式肯定是不一样的
      • updater 它作为一个参数,让不同的平台传参进来,定制它自己的一个实现方式
      • 所以,这就是为什么要封装传参
  • 接下来,进入到 Component.prototype.forceUpdate

    Component.prototype.forceUpdate = function(callback) {
      this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
    };
    
    • 这个跟 setState 其实是一样的,它是调用了 this.updater.enqueueForceUpdate(this, callback, 'forceUpdate'); 这个方法
    • 这个API不是很常用,它是强制 react Componet 更新一遍,即便你的state没有进行更新
  • 接下来,在 DEV 环境的判断下,有两个即将被废弃的API

    • 一个是 isMounted
    • 另外一个是 replaceState
  • 到这里为止,可以看到 Component 的定义已经结束了, 它只有这么一点东西

  • 这个 Component 的定义,只是用来帮助我们去承载一些信息的

  • 没有任何的其他含义,也没有任何关于生命周期相关的一些方法, 就是这么简洁

2.2 PureComponent

  • 其实可以认为它是继承于 Component

  • 其实也没多少可以继承的东西,它们接收的东西也是一模一样的

    /**
     * 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};
    
    • 使用这个 ComponentDummy 实现了一个类似于简单的继承的方式
    • 它 new了一个 ComponentDummy,它是一个空的类
    • 它的 constructor 指向 PureComponent 自己, 这其实就是一个实现继继的过程
    • 之后把 Component.prototype 上面的属性拷贝到 pureComponentPrototype 上面
    • 唯一的一个区别是 pureComponentPrototype.isPureReactComponent = true;
    • 通过这个属性来标识,继承自这个类的组件,它是一个 PureComponent
    • 在后续更新的过程中,react-dom 主动的去判断它是不是一个 PureComponent
    • 然后去根据 props 是否更新来判断这个组件是否需要更新
知识梳理------React组件性能优化 React 组件性能优化最佳实践 React 组件性能优化的核心是减少渲染真实 DOM 节点的频率,减少 Virtual DOM 比对的频率。 1. 组件卸载前进行清理操作 在组件中为 window 注册的全局事件, 以及定时器, 在组件卸载前要清理掉, 防止组件卸载后继续执行影响应用性能. 需求:开启定时器然后卸载组件,查看组件中的定时器是否还在运行。 import React, { useState, useEffect } from "react" import ReactDOM from "reac 阅读详情

相关推荐

React 源码阅读入门1(JSX与Component)

基本信息 React的github地址 可选择分支对应的版本进行克隆。此处使用当前的master分支既v16.12.0进行学习。 项目目录结构如下,最重要的react与react-dom源码,位于package文件夹下对应目录的src文件夹中。 react源码的目录结构 react/src/React.js 创建React对象,该对象包括我们平时开发中常用的react api,例如C...

w19960808的博客 480

react知识点之Component和PureComponent深度解析

Component和PureComponent的区别 介绍 React.PureComponent 与 React.Component 几乎完全相同,但 React.PureComponent 通过props和state的浅对比来实现 shouldComponentUpate()。 在PureComponent中,如果包含比较复杂的数据结构,可能会因深层的数据不一致而产生错误的否定判断,导致界面得不到更新。 如果定义了 shouldComponentUpdate(),无论组件是否是 PureCompone

小糖豆 6609

React源码解析----createElement + Component + PureComponent

title: React源码解析----createElement + Component + PureComponent tags: - 源码 - React 上一篇介绍了React的Api,今天介绍createElement和React的Component相关操作。看了很多其他人的博客,对于React16的fiber架构还是无法了解,尽管我知道他很牛逼。发现了解React的源码还是需要从渲...

qq_38606793的博客 597

React PureComponent介绍与使用

前言 介绍之前可以先看下shouldComponentUpdate介绍 PureComponent介绍 React15.3中新加了一个 PureComponent 类,顾名思义, pure 是纯的意思, PureComponent 也就是纯组件,取代其前身 PureRenderMixin , PureComponent 是优化 React 应用程序最重要的方法之一,易于实施,只要把继承类从 Com...

Boboy 6946

React性能优化:PureComponent与memo实战解析

虚拟DOM和组件重渲染机制是React性能优化的核心概念。React默认采用保守的渲染策略,父组件状态变化会触发整个子树的重渲染,这在复杂组件树和高频更新场景下会产生性能瓶颈。通过浅比较(shallow compare)实现的PureComponent和React.memo,能有效避免不必要的重渲染,特别适用于展示型组件和大型列表场景。优化时需要遵循不可变数据原则,配合useCallback保持引用稳定,并通过性能分析工具定位真正的瓶颈。这些技术在电商列表、实时仪表盘等高频交互场景中能显著提升帧率,从工程实

weixin_30897079的博客 339

洞悉细节!react 16.8.6源码分析-2 组件构造与获取调用栈

前言 作为一个前端页面仔和需求粉碎机,在日常的工作中重复雷同的业务需求,能够获得的提高是很有限的。要想跳出此山中,开阔新视野,笔者墙裂建议大家阅读市面上顶尖开源库的源码。这是学习和掌握js语言特性的绝佳机会(前端发展到现在,大型应用高度依赖框架,正常情况下普通开发者是没有机会接触底层的语言特性),同时也是深刻理解框架底层思维的契机。这里笔者选择react第一个开刀,市面上不少关于react源码分析的文章要么过于老旧,要么只截取部分代码或者是伪代码,笔者这里将选取react的16.8.6版本作为示例,从第0行

广兰路地铁的博客 951

React Component和Purecomponent区别

PureComponent是一个优化过的组件类,它默认实现了一个浅比较的shouldComponentUpdate函数。当组件的props或state发生变化时,PureComponent会对新旧props和state进行浅比较,如果没有变化,则不重新渲染组件。Component是一个普通的组件类,它的shouldComponentUpdate函数默认返回true,意味着每次组件的props或state发生变化时都会重新渲染组件。这可能会导致性能问题,特别是当组件包含大量子组件时。

weixin_59525879的博客 720

React中的PureComponent:优化你的React组件

PureComponent是React中的一个特殊组件类,它是React.Component的一个子类。与普通的React组件不同,PureComponent具有一种优化机制,可以自动执行浅比较来避免不必要的渲染。当组件的props或state发生变化时,React会检查前后两次的props和state是否相等,如果相等,则不会进行重新渲染,从而提高应用的性能。PureComponent是React中的一个优化工具,可以帮助你避免不必要的组件重新渲染。

YabClass的博客 323

React 源码系列-Component、PureComponent、function Component 分析

本文基于 React v16.8.6 以下是使用三种 Component 创建的一个组件 import React, { Component, PureComponent } from 'react'; // function Component function FuncComp() { return <div>FuncComp</div> } // Compone...

止水聊技术 1220

CHNS数据库下载与使用指南:从申请到导入的全流程解析

面板数据是经济学与公共卫生实证研究的重要支撑。中国健康与营养调查(CHNS)自1989年持续追踪中国居民的家庭与个人健康、营养及经济行为,为研究者提供了跨度近三十年的纵向微观数据。理解CHNS的数据组织原理与申请机制,是高效利用该数据的前提。该数据广泛适用于健康经济学、膳食营养分析及公共政策评估等场景。围绕CHNS的下载流程,完整梳理了注册申请、数据文件解析以及Stata、R、Python三种工具的读取方法,并针对邮箱验证、文件损坏、ID匹配等常见问题提供排查建议,帮助研究者快速建立数据处理基础。

weixin_33624741的博客 287

lumerical-环形谐振器

利用mode求解器优化得到所需的环的总长度,即环形器的半径,然后通过varFDTD得到光场分布和透过率.

m0_61776728的博客 2189

React性能优化:PureComponent与Component核心差异解析

在React开发中,组件性能优化是提升应用流畅度的关键。PureComponent通过实现shouldComponentUpdate的浅比较机制,自动过滤不必要的渲染,相比普通Component能显著提升性能。浅比较(shallow comparison)是React的核心概念之一,它只比较对象的第一层属性,适用于props和state变化不频繁的场景。这种机制特别适合大型列表项和静态展示组件,能有效减少60%以上的无效渲染。理解PureComponent与Component的底层差异,掌握不可变数据(Im

weixin_34241036的博客 297

Ubuntu声卡检测与故障排查:从基础命令到驱动修复

本文详细介绍了在Ubuntu系统中进行声卡检测与故障排查的完整流程。从使用lspci、aplay等基础命令识别硬件,到排查驱动冲突、修复权限问题,再到调整PulseAudio高级配置,提供了一套系统性的解决方案。文章结合实战案例,帮助用户快速诊断并解决Ubuntu系统常见的“无声”问题,恢复音频功能。

g2h3i4j5的博客 229

ReactNative组件性能优化:Component与PureComponent对比

在React和ReactNative开发中,组件渲染性能是构建高效应用的关键。Component作为基础类组件,会在每次父组件更新时无条件重渲染,而PureComponent通过浅比较(shallow compare)机制智能判断是否需要更新,显著减少不必要的渲染开销。浅比较通过对比props和state的第一层属性引用,特别适合展示型组件和长列表优化场景。性能优化实践中,合理使用PureComponent可以提升移动端应用的流畅度,特别是在处理复杂组件树和频繁更新的交互界面时。结合React DevToo

341

从零到一:龙芯杯参赛全攻略(含北理工学长经验PDF、B站培训视频与开源代码合集)

本文详细介绍了龙芯杯全国大学生计算机系统能力大赛的参赛全攻略,包括资源整合、技能树构建、团队协作和避坑指南。提供北理工学长经验PDF、B站培训视频与开源代码合集,帮助参赛者从零基础到站上领奖台。重点解析如何高效获取优质资源、避开新手常见陷阱及构建可落地的学习路径,助力普通学生系统学习CPU设计。

weixin_26802933的博客 542

研究生研一学习机器学习ML、深度学习DL的规划

研究生学习机器学习DL、深度学习DL的规划 保上研之后也没有很好规划自己的学习路线,看到b站上的一位清华博士讲述他本科也是机械跨考计算机的学习路线,所以记录下来,从现在开始按照规划来一点一点地做好。 掌握python(推荐一周) 1.1 面向对象编程 廖雪峰python网站: https://www.liaoxuefeng.com 1.2 数据分析Numpy numpy 100题: https://www.yanxishe.com/columnDetail/24784 1.3数据分析pandas pan

没有最好,只有更好 3100

React 源码漂流(三)之 PureComponent

一、PureComponentPureComponent 最早在 React v15.3 版本中发布,主要是为了优化 React 应用而产生。classCounter...

我本可以容忍阳光,如果我不曾见过太阳,然而阳光已使我荒凉,成为更新的荒凉。 659

MATLAB基础应用精讲-【强化学习】Actor - Critic 算法(附python代码实现)

这种架构结合了策略梯度方法(Policy - Gradient Methods)和价值函数估计方法(Value Function Estimation Methods)的优点。在强化学习中,智能体(Agent)需要通过与环境(Environment)的交互来学习最优的行为策略,以获得最大的累积奖励(Cumulative Reward)。

qq_36130719的博客 366

React源码16.12.x --- Component 与 PureComponent

如何区分纯组件 React PureComponent 源码解析 Component & PureComponent 这两个类基本相同,唯一的区别是PureComponent的原型上多了一个标识。 这是检查组件是否需要更新的一个判断,ctor就是你声明的继承自Component or PureComponent的类,他会判断你是否继承自PureComponent,如果是的话就shallow...

WRian_Ban的小晴天 524

微搭低代码实现用户登录及注册功能

在小程序开发中,我们可以拿到微信用户的openid,openid可以作为用户的唯一标识,在查询数据的时候可以进行数据过滤实现查询自己提交的数据。那微搭中是否也有openid这个概念,可以获取用户自己提交的数据呢? 答案是肯定的,那要怎么去做呢?思路是先创建一个数据源方法,在数据源中返回openid,然后低代码中可以调用数据源的方法并且赋值给全局变量,这样在后续的业务中从全局变量就可以获取openid了,方便做数据权限的控制。 为了实现这个目的,我们从创建数据源开始。 创建数据源 我们先创建一个用户管理的数据

低代码布道师的博客 3000

网络安全与黑客攻防常见设备:前置机、跳板机、堡垒机与肉鸡

前置机、跳板机、堡垒机和肉鸡,这些看似冷僻的技术名词,实则是网络安全与黑客攻防战中的关键角色。它们有的守护着企业的数字Pltform,保卫网络安全;有的则成为黑客的跳板,游走于灰色地带。

网络技术联盟站 967

React 源码解析之总览

本小书大部分内容来自作者 Jokcy 的 《React 源码解析》: react.jokcy.me/ 本文已同步在我的博客: ruizhengyun.cn/blog/post/2… 感谢 Jokcy 让我深度了解 React。如他所说,在决定阅读 React 源码时认为不会是一件很难的事,但是真正开始阅读之后才发现,事情没那么简单,因为需要足够的耐心、能够独立思考和静下心来(因为你会碰到之前编码...

weixin_34008933的博客 216

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

React16源码解读:开篇带你搞懂几个面试考点

框架的部分实现细节也常成为面试中的考察要点,因此,一方面为了应付面试官的连番追问,另一方面为了提升自己的技能水平,还是有必要对框架的底层实现原理有一定的涉猎。当然对于主攻哪门技术栈没有严...

frontend_frank的博客 480

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

React 的 PureComponent Vs Component

它们几乎完全相同,但是PureComponent通过prop和state的浅比较来实现shouldComponentUpdate,某些情况下可以用PureComponent提升性能 一、所谓浅比较(shallowEqual),即react源码中的一个函数,然后根据下面的方法进行是不是PureComponent的判断,帮我们做了本来应该我们在shouldComponentUpdate中做的事情 if...

weixin_34345560的博客 103

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

react 源码学习

源码学习记录1. React Api2. React中的创建更新3. React调度过程(Fiber Scheduler)4. 组件如何进行更新5. 组件更新完成后进行的操作1. 虚拟Dom对比2. 渲染中出现错误的处理过程6. 真实Dom更新7. 各种功能的实现(content,ref,hydrate...)8. Suspense (超前体验)9. Hooks 1. React Api Fibe...

七元八元 498
上一篇: React16源码: JSX2JS及React.createElement源码实现
下一篇: React16源码: createRef与forwardRef源码实现
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值