当前位置: 首页 > news >正文

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的调用,在源码的注释中
http://www.lryc.cn/news/287020.html

相关文章:

  • Hive-SQL语法大全
  • 编译原理2.3习题 语法制导分析[C++]
  • JUC-CAS
  • Effective C++——关于重载赋值运算
  • vscode debug
  • 数据库选型其实技术维度不太重要
  • 【C++】入门(二)
  • Nginx 代理服务路径带/和不带/的问题
  • C# CefSharp 输入内容,点击按钮,并且滑动。
  • 历经15年,比特币以强势姿态进军华尔街!270亿美元投资狂潮引发市场震荡!
  • GBASE南大通用的接口程序GBase ADO.NET
  • 算法训练营Day57(回文子串--总结DP)
  • 使用OpenCV从一个矩阵提取子矩阵
  • 微信云托管:基本使用指南
  • WEB前端IDE的使用以及CSS的应用
  • python中排序函数sorted的简单运用
  • k8s的helm
  • [MySQL]基础的增删改查
  • 简易播放器 以及触发的异常
  • 【Flutter跨平台插件开发】如何实现kotlin跟C++的相互调用
  • Apache SeaTunnel社区荣获“2023快速成长开源项目”奖项
  • Unity 桥接模式(实例详解)
  • Xftp连接不上Linux虚拟机的原因解决方法
  • 代码随想录刷题笔记 DAY12 | 二叉树的理论基础 | 二叉树的三种递归遍历 | 二叉树的非递归遍历 | 二叉树的广度优先搜索
  • Linux问题 apt-get install时 无法解析域名“cn.archive.ubuntu.com”
  • 蓝桥--鸡哥的购物挑战OJ(4169)
  • MySQL--删除数据表(6)
  • 常用界面设计组件 —— 时间日期与定时器
  • GO 中高效 int 转换 string 的方法与高性能源码剖析
  • YOLOv7调用摄像头检测报错解决