React16源码: React中的IndeterminateComponent的源码实现
IndeterminateComponent
1 )概述
- 这是一个比较特殊的component的类型, 就是还没有被指定类型的component
- 在一个fibrer被创建的时候,它的tag可能会是
IndeterminateComponent
- 在 packages/react-reconciler/src/ReactFiber.js 中,有一个方法
createFiberFromTypeAndProps
中,一开始就声明了let fiberTag = IndeterminateComponent; let resolvedType = type; // 一开始 if (typeof type === 'function') {// 在 function 下只是判断了 constructor是否存在// 在不存在的时候,是否认为它是一个 FunctionComponent 呢,实际上并没有// 实际上我们写的任何一个 function component 一开始就是 IndeterminateComponent 类型if (shouldConstruct(type)) {// 存在,则赋值为 ClassComponentfiberTag = ClassComponent;} } else if (typeof type === 'string') {fiberTag = HostComponent; } else {// 省略 }
- 在最终调用
createFiber
创建 Fiber 对象
2 )源码
定位到 packages/react-reconciler/src/ReactFiber.js
进入 mountIndeterminateComponent 方法
//
function mountIndeterminateComponent(_current,workInProgress,Component,renderExpirationTime,
) {// 首先判断 _current 是否存在,存在则进行初始化操作// 因为只有在第一次渲染的时候,才有 indeterminate component 这种情况// 经过第一次渲染之后,我们就会发现 indeterminate component 的具体的类型// 这种情况,可能是中途抛出一个 error 或 promise 等情况,比如 Suspense 组件// 这时候初始化是为了 去除 _current 和 workInProgress 相关联系,因为需要重新进行初次渲染的流程if (_current !== null) {// An indeterminate component only mounts if it suspended inside a non-// concurrent tree, in an inconsistent state. We want to treat it like// a new mount, even though an empty version of it already committed.// Disconnect the alternate pointers._current.alternate = null;workInProgress.alternate = null;// Since this is conceptually a new fiber, schedule a Placement effectworkInProgress.effectTag |= Placement;}const props = workInProgress.pendingProps;const unmaskedContext = getUnmaskedContext(workInProgress, Component, false);const context = getMaskedContext(workInProgress, unmaskedContext);prepareToReadContext(workInProgress, renderExpirationTime);prepareToUseHooks(null, workInProgress, renderExpirationTime);let value;if (__DEV__) {if (Component.prototype &&typeof Component.prototype.render === 'function') {const componentName = getComponentName(Component) || 'Unknown';if (!didWarnAboutBadClass[componentName]) {warningWithoutStack(false,"The <%s /> component appears to have a render method, but doesn't extend React.Component. " +'This is likely to cause errors. Change %s to extend React.Component instead.',componentName,componentName,);didWarnAboutBadClass[componentName] = true;}}if (workInProgress.mode & StrictMode) {ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);}ReactCurrentOwner.current = workInProgress;value = Component(props, context); } else {value = Component(props, context); // 调用 Component 方法}// React DevTools reads this flag.workInProgress.effectTag |= PerformedWork;// 符合这个条件,认为是 ClassComponent, 具有 render 方法if (typeof value === 'object' &&value !== null &&typeof value.render === 'function' &&value.$$typeof === undefined) {// Proceed under the assumption that this is a class instanceworkInProgress.tag = ClassComponent; // 这里认为它是一个 ClassComponent// Throw out any hooks that were used.resetHooks();// Push context providers early to prevent context stack mismatches.// During mounting we don't know the child context yet as the instance doesn't exist.// We will invalidate the child context in finishClassComponent() right after rendering.let hasContext = false;if (isLegacyContextProvider(Component)) {hasContext = true;pushLegacyContextProvider(workInProgress);} else {hasContext = false;}workInProgress.memoizedState =value.state !== null && value.state !== undefined ? value.state : null;const getDerivedStateFromProps = Component.getDerivedStateFromProps;if (typeof getDerivedStateFromProps === 'function') {applyDerivedStateFromProps(workInProgress,Component,getDerivedStateFromProps,props,);}adoptClassInstance(workInProgress, value);mountClassInstance(workInProgress, Component, props, renderExpirationTime);return finishClassComponent(null,workInProgress,Component,true,hasContext,renderExpirationTime,);} else {// 否则按照 FunctionComponent 来渲染// Proceed under the assumption that this is a function componentworkInProgress.tag = FunctionComponent; value = finishHooks(Component, props, value, context);if (__DEV__) {if (Component) {warningWithoutStack(!Component.childContextTypes,'%s(...): childContextTypes cannot be defined on a function component.',Component.displayName || Component.name || 'Component',);}if (workInProgress.ref !== null) {let info = '';const ownerName = ReactCurrentFiber.getCurrentFiberOwnerNameInDevOrNull();if (ownerName) {info += '\n\nCheck the render method of `' + ownerName + '`.';}let warningKey = ownerName || workInProgress._debugID || '';const debugSource = workInProgress._debugSource;if (debugSource) {warningKey = debugSource.fileName + ':' + debugSource.lineNumber;}if (!didWarnAboutFunctionRefs[warningKey]) {didWarnAboutFunctionRefs[warningKey] = true;warning(false,'Function components cannot be given refs. ' +'Attempts to access this ref will fail.%s',info,);}}if (typeof Component.getDerivedStateFromProps === 'function') {const componentName = getComponentName(Component) || 'Unknown';if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) {warningWithoutStack(false,'%s: Function components do not support getDerivedStateFromProps.',componentName,);didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true;}}if (typeof Component.contextType === 'object' &&Component.contextType !== null) {const componentName = getComponentName(Component) || 'Unknown';if (!didWarnAboutContextTypeOnFunctionComponent[componentName]) {warningWithoutStack(false,'%s: Function components do not support contextType.',componentName,);didWarnAboutContextTypeOnFunctionComponent[componentName] = true;}}}reconcileChildren(null, workInProgress, value, renderExpirationTime);return workInProgress.child;}
}
- 基于上述判断条件 能认定是一个 ClassComponent,后续渲染一定会按照 ClassComponent 进行
if ( typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined ){}
- 现在来测试一下,看下 function component 是否可以执行
import React from 'react'export default function TestIndeterminationComponent() {return {componentDidMount() {console.log('invoker')},render() {return <span>aaa</span>}} }
- 上述都能正常显示,以及打印 console 输出
- 也就是说,对于一个 function component, 如果里面 return 的对象,具有 render 方法
- 就认为它是一个 class component 一样的类型,去使用它
- 并且在里面声明的生命周期方法都会被它调用
- 这是
IndeterminateComponent
的特性
- 在最初我们渲染的时候,所有的 function component 都是
IndeterminateComponent
的类型 - 在第一次渲染之后,我们根据渲染类型的返回,最终得到具体类型
- 可以通过 function component 返回一个对象的方式去渲染一个类似 classComponent 这样的类型
- 注意,一般不推荐这么写
相关文章:
React16源码: React中的IndeterminateComponent的源码实现
IndeterminateComponent 1 )概述 这是一个比较特殊的component的类型, 就是还没有被指定类型的component在一个fibrer被创建的时候,它的tag可能会是 IndeterminateComponent在 packages/react-reconciler/src/ReactFiber.js 中,有…...

SpringBoot:详解Bean生命周期和作用域
🏡浩泽学编程:个人主页 🔥 推荐专栏:《深入浅出SpringBoot》《java项目分享》 《RabbitMQ》《Spring》《SpringMVC》 🛸学无止境,不骄不躁,知行合一 文章目录 前言一、生命周期二…...

【图解数据结构】顺序表实战指南:手把手教你详细实现(超详细解析)
🌈个人主页:聆风吟 🔥系列专栏:图解数据结构、算法模板 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 一. ⛳️线性表1.1 🔔线性表的定义1.2 🔔线性表的存储结构 二. ⛳️顺序表…...

WordPress怎么禁用文章和页面古腾堡块编辑器?如何恢复经典小工具?
现在下载WordPress最新版来搭建网站,默认的文章和页面编辑器,以及小工具都是使用古腾堡编辑器(Gutenberg块编辑器)。虽然有很多站长说这个编辑器很好用,但是仍然有很多站长用不习惯,觉得操作太难了…...

【HarmonyOS】掌握布局组件,提升应用体验
从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是…...
第4周:Pytorch——综合应用和实战项目 Day 28-30: 学习资源和社区参与
第4周:综合应用和实战项目 Day 28-30: 学习资源和社区参与 在这个阶段,我们将探索更多的学习资源并鼓励参与PyTorch和TensorFlow的社区,以进一步提升技术和融入开发者社群。 学习资源: 论文:阅读最新的机器学习和深度…...

TypeScript教程(一)在vscode中的配置TypeScript环境
TypeScript教程(一)在vscode中的配置TypeScript环境 文章目录 TypeScript教程(一)在vscode中的配置TypeScript环境一、前言二、具体步骤1、Node.js安装2、TypeScript安装3、helloworld 一、前言 未来的开发者们请上座,…...

sshpass的安装与使用
一.简介 1.定义: ssh 登陆不能在命令行中指定密码,sshpass 的出现则解决了这一问题。它允许你用 -p 参数指定明文密码,然后直接登录远程服务器,它支持密码从命令行、文件、环境变量中读取。 2.使用 sshpass 原因 使用 sshpass…...

Excel·VBA合并工作簿2
其他合并工作簿的方法,见之前的文章《ExcelVBA合并工作簿》 目录 8,合并文件夹下所有工作簿中所有工作表,按表头汇总举例 8,合并文件夹下所有工作簿中所有工作表,按表头汇总 与之前的文章《ExcelVBA合并工作簿&#x…...

linux内核原理--分页,页表,内核线性地址空间,伙伴系统,内核不连续页框分配,内核态小块内存分配器
1.分页,页表 linux启动阶段,最初运行于实模式,此阶段利用段寄存器,段内偏移,计算得到物理地址直接访问物理内存。 内核启动后期会切换到保护模式,此阶段会开启分页机制。一旦开启分页机制后,内…...

【MongoDB】下载安装、指令操作
目录 1.下载安装 2.指令 2.1.基础操作指令 2.2.增加 2.3.查询 2.4.修改 2.5.删除 前言: 关于MongoDB的核心概念请移步: 【文档数据库】ES和MongoDB的对比-CSDN博客 1.下载安装 本文以安装Windows版本的mongodb为例,Linux版本的其实…...
k8s-pvc/pv扩容记录
背景 一次聊天过程中,对方提及pvc的扩容,虽然有注意过 storageclass 有个AllowVolumeExpansion的配置(有些csi插件是不支持该配置的,比如local-volume-provisoner),但是没有实际用过,所以还是心…...
关于Unity插件TriLib使用的一点儿心得
最近做一个项目的时候,由于要求动态加载fbx或者glb等格式文件,而我们自己开发加载插件难度又有点大,所以最后使用了TriLib这个插件,现在说一点使用心得。 由于文件加载之后要对加载的内容进行复制,比如加载一个柱子&am…...
计算机二级Python基本排序题-序号45(补充)
1. 文件"singup.txt”中保存了若干条参加运动会学生的报名记录,每条记录的形式为“班级号_学号”,例如"A1_12”,将每个班级报名情按参加运动会人数从多到少排列(假设不存在人数相同的情况)并输出,…...

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例4-6 fieldset
代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>fieldset</title> </head><body> <form action"#"><fieldset><legend>学生信息</legend>姓名:&…...
html渲染优先级
在前端开发中,优先布局是指在设计和构建页面时,将页面的各个部分按照其重要性和优先级进行排序,并依次进行布局和开发。这种方法可以帮助开发团队在项目初期就确定页面结构的核心部分,从而更好地掌控项目的整体进度和优先级。且确…...

linux 更新镜像源
打开终端,备份一下旧的 源 文件,以防万一 cd /etc/apt/ ls sudo cp sources.list sources.list.bak ls然后打开清华大学开源软件镜像站 搜索一下你的linux发行版本,我这里是ubuntu发行版本 点击这个上面图中的问号 查看一下自己的版本号&a…...

【征服Redis12】redis的主从复制问题
从现在开始,我们来讨论redis集群的问题,在前面我们介绍了RDB和AOF两种同步机制,那你是否考虑过这两个机制有什么用呢?其中的一个重要作用就是为了集群同步设计的。 Redis是一个高性能的键值存储系统,广泛应用于Web应用…...
php函数 一
一 自动加载 1.1 __autoload(string $class) 类自动加载,7.2版本之后废弃。可使用sql_autoload_register()注册方法实现。 类自动加载,无返回值。 #php7.2之前function __autoload($class) {if(strpos($class, CI_) ! 0){if (file_exists(APPPATH . …...
监督学习 - 梯度提升回归(Gradient Boosting Regression)
什么是机器学习 梯度提升回归(Gradient Boosting Regression)是一种集成学习方法,用于解决回归问题。它通过迭代地训练一系列弱学习器(通常是决策树)来逐步提升模型的性能。梯度提升回归的基本思想是通过拟合前一轮模…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...