网站首页 > 技术文章 正文
背景
最近在封装提醒组件时,因为提醒组件元素是动态创建的,需要添加在当前组件的外部(不在root中),因为这种提醒的组件是全局使用的,和业务关系不大,并且是根据需要动态使用;
发现有用 ReactDOM.createPortal,而有的使用 ReactDOM.render,于是在网上找这俩的区别,也没很好的资料。于是详细的看了官网,并写了一些 demo 来测试和验证自己的理解。
定义
render()
ReactDOM.render(element, container[, callback])
在提供的 container 里渲染一个 React 元素,并返回对该组件的引用(或者针对无状态组件返回 null)。
如果 React 元素之前已经在 container 里渲染过,这将会对其执行更新操作,并仅会在必要时改变 DOM 以映射最新的 React 元素。
如果提供了可选的回调函数,该回调将在组件被渲染或更新之后被执行。
createPortal()
ReactDOM.createPortal(child, container)
创建 portal。Portal 将提供一种将子节点渲染到 DOM 节点中的方式,该节点存在于 DOM 组件的层次结构之外。
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。
疑问
render()目前没有什么疑问,主要是 createPortal 的描述有些奇怪。
1.“该节点存在于 DOM 组件的层次结构之外”是什么意思? 2.难道使用 render 不能把子节点渲染到父组件以外的 DOM 节点吗? 3.为什么说 portal 的这个方案“优秀”? 4.两者区别是什么?
这四个问题你都知道答案,就没必要往下看了。
解答
1.“该节点存在于 DOM 组件的层次结构之外”是什么意思?
这个很好理解,通常我们是把组件都渲染在页面上一个id为root的div容器中。这里所说的“之外”的意思,就是这个组件不渲染在root中,在一个新的容器中,也可以直接放到body最后。
2.难道使用 render 不能把子节点渲染到父组件以外的 DOM 节点吗?
能!!!之前一直以为 render 只能使用一次,或者不能在额外的节点重新进行渲染,结果都不是。
3.为什么说 portal 的这个方案“优秀”? 两者的区别是什么?
既然 render 也能在新的容器中渲染组件,为什么还要再新增一个 createPortal 方法呢,意义在哪?
意义在捕获事件,事件冒泡就不详细解释了。在使用 createPortal 渲染时,比如组件 A,虽然它渲染在一个新的元素中,但调用 A 的组件 B 是可以捕获 A 中的事件。如果使用 render 就无法捕获。
比如 B 的根元素上有一个 click 事件,如果使用 render 渲染 A,点击 A 的区域,B 的 click 事件是不会触发的;但如果使用 createPortal,则会触发。
demo
import React from "react";
import ReactDOM from "react-dom";
let root;
class TestPortal extends React.PureComponent {
constructor(props) {
super(props);
root = document.getElementById("root1");
}
componentDidMount() {}
render() {
// createPortal换成render测试
return ReactDOM.createPortal(this.props.children, root);
}
}
export default TestPortal;
// 在APP.js中调用
<div
onClick={() => {
alert("触发了");
}}
>
hello
<TestPortal>
<h1>一个新的元素</h1>
</TestPortal>;
</div>;
这就是 createPortal 的奇特之处,虽然和父组件不在一个 dom 分支上,事件却会别捕获。
什么时候使用createPortal
一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框;
猜你喜欢
- 2024-09-20 Vue.js常见的20道前端面试题及答案
- 2024-09-20 AI面试官:我能胜任React(二)(我能胜任这份工作吗)
- 2024-09-20 70个JavaScript知识点详细总结(上)【实践】
- 2024-09-20 学会使用Vue JSX,一车老干妈都是你的
- 2024-09-20 字节P8大佬爆肝整理,一文带你梳理React面试题!
- 2024-09-20 2024前端面试真题之—VUE篇(2020web前端经典面试题 vue)
- 2024-09-20 JS事件绑定的常用方式实例总结(js事件绑定的四种方式)
- 2024-09-20 JavaScript 的基本术语大全(javascript的基本概念)
- 2024-09-20 React18内核探秘:手写React高质量源码迈向高阶开发(超清完结)
- 2024-09-20 React三浅一深之ES6(一)(三浅是什么意思)
- 1514℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 564℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 508℃MySQL service启动脚本浅析(r12笔记第59天)
- 486℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 485℃启用MySQL查询缓存(mysql8.0查询缓存)
- 465℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 445℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 442℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)