React16源码: React中的PortalComponent创建, 调和, 更新的源码实现

本文主要是介绍React16源码: React中的PortalComponent创建, 调和, 更新的源码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PortalComponent


1 )概述

  • React Portal之所以叫Portal,因为做的就是和“传送门”一样的事情
  • render到一个组件里面去,实际改变的是网页上另一处的DOM结构
  • 主要关注 portal的创建, 调和, 更新过程

2 )源码

定位到 packages/react-dom/src/client/ReactDOM.js#L576

function createPortal(children: ReactNodeList,container: DOMContainer,key: ?string = null,
) {invariant(isValidContainer(container),'Target container is not a DOM element.',);// TODO: pass ReactDOM portal implementation as third argumentreturn ReactPortal.createPortal(children, container, null, key);
}
  • 这里调用的是 ReactPortal.createPortal, 进入

    // packages/shared/ReactPortal.js#L14
    export function createPortal(children: ReactNodeList,containerInfo: any,// TODO: figure out the API for cross-renderer implementation.implementation: any,key: ?string = null,
    ): ReactPortal {return {// This tag allow us to uniquely identify this as a React Portal$$typeof: REACT_PORTAL_TYPE,key: key == null ? null : '' + key,children,containerInfo, // dom 挂载节点implementation,};
    }
    
    • 这里返回一个对象,类似于 ReactElement
    • 区别在于 $$typeofcontainerInfo 需要的挂载点
  • 对于 REACT_PORTAL_TYPE 类型的组件在 reconcile 时, 看下具体操作, 找到 reconcileSinglePortal

    // packages/react-reconciler/src/ReactChildFiber.js#L1171
    function reconcileSinglePortal(returnFiber: Fiber,currentFirstChild: Fiber | null,portal: ReactPortal,expirationTime: ExpirationTime,
    ): Fiber {const key = portal.key; // 当前的 keylet child = currentFirstChild;// 如果 存在 child, 对比 child.key === keywhile (child !== null) {// TODO: If key === null and child.key === null, then this only applies to// the first item in the list.if (child.key === key) {// 关注这里,有 containerInfo 的对比,portal 需要关心渲染到的节点是否有变化// 如果节点有变化,那么这个 portal 的渲染过程也会有变化// 都符合,说明老节点都可以复用if (child.tag === HostPortal &&child.stateNode.containerInfo === portal.containerInfo &&child.stateNode.implementation === portal.implementation) {deleteRemainingChildren(returnFiber, child.sibling); // 删除其他节点// 通过 useFiber 复用这个节点const existing = useFiber(child,portal.children || [],expirationTime,);existing.return = returnFiber;return existing;} else {// key相同,但是不符合上述if, 没法复用,删除干净deleteRemainingChildren(returnFiber, child);break;}} else {// key 不同,删除当前节点deleteChild(returnFiber, child);}child = child.sibling;}// 创建一个 portal 的 fiber 对象const created = createFiberFromPortal(portal,returnFiber.mode,expirationTime,);created.return = returnFiber;return created;
    }
    
  • 对于更新一个portal节点,进入 updatePortalComponent

    // packages/react-reconciler/src/ReactFiberBeginWork.js#L1322
    function updatePortalComponent(current: Fiber | null,workInProgress: Fiber,renderExpirationTime: ExpirationTime,
    ) {// 挂载点处理pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);const nextChildren = workInProgress.pendingProps; // 这里 pendingProps 是 childrenif (current === null) {// Portals are special because we don't append the children during mount// but at commit. Therefore we need to track insertions which the normal// flow doesn't do during mount. This doesn't happen at the root because// the root always starts with a "current" with a null child.// TODO: Consider unifying this with how the root works.workInProgress.child = reconcileChildFibers(workInProgress,null,nextChildren,renderExpirationTime,);} else {reconcileChildren(current,workInProgress,nextChildren,renderExpirationTime,);}return workInProgress.child;
    }
    
    • 之前梳理过的 API 不再赘述
    • 一些API的调用,在源码的注释中

这篇关于React16源码: React中的PortalComponent创建, 调和, 更新的源码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/628778

相关文章

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg