React Portals
什么是React Portals
React Portals(React 门户)是 React 提供的一种机制,用于将组件渲染到 DOM 树中的不同位置,而不受组件层次结构的限制。它允许你将一个组件的渲染内容“传送”到 DOM 结构中的任何位置,通常用于处理一些特殊的 UI 布局需求,如弹出窗口、模态框、通知框等。
React Portals 的主要优势是它可以在组件树中的某一级组件上渲染内容,而不受该组件的父组件或祖先组件的影响。这在处理全局或跨层级的 UI 元素时非常有用,因为它不会破坏组件的层次结构。
作用
React Portals 的主要作用是允许你将组件的渲染内容渲染到 DOM 结构中的不同位置,而不受组件层次结构的限制。它有几个重要的应用场景和作用:
-
处理全局 UI 元素: React Portals 允许你将 UI 元素渲染到应用的根 DOM 之外,这对于创建全局的 UI 元素非常有用,比如模态框、通知框、工具提示等。这些元素可以浮在应用的其他组件之上,而不会受到组件嵌套结构的影响。
-
处理层叠上下文: 有些 CSS 样式属性(如
z-index)会创建层叠上下文,限制了某些元素的显示顺序。使用 React Portals 可以将元素渲染到指定的 DOM 节点上,从而绕过这些层叠上下文的限制,实现更复杂的 UI 布局。 -
处理复杂的 UI 布局: 在某些情况下,需要将组件的渲染内容插入到 DOM 结构的特定位置,以满足设计或布局需求。React Portals 允许你在不改变组件层次结构的情况下实现这些需求。
-
提高可重用性: 使用 React Portals 可以将通用的 UI 组件(如模态框或通知框)封装为可重用的组件,使其可以在不同的应用中使用,并且不需要关心组件的放置位置。
原理
React Portals 的原理涉及到了 React 的虚拟 DOM以及底层的 DOM 操作。
-
创建虚拟 DOM 树: 在 React 组件中,你可以使用
ReactDOM.createPortal函数来创建一个 Portal。这个函数接受两个参数:要渲染的内容(通常是 React 元素)和目标 DOM 元素。 -
将虚拟 DOM 渲染到目标 DOM 元素: 当你调用
ReactDOM.createPortal时,React 会创建一个新的虚拟 DOM 子树,包括你传递的内容。然后,React 会使用底层的 DOM 操作,将这个虚拟 DOM 子树渲染到指定的目标 DOM 元素上,而不是按照通常的组件层次结构将其渲染到根 DOM 上。 -
维护 React 组件的状态: Portal 内部的 React 组件仍然保持其正常的生命周期和状态管理。这意味着你可以在 Portal 内部使用状态、事件处理程序等 React 功能。
-
脱离组件层次结构: Portal 允许你将内容渲染到组件树之外的位置,这意味着你可以创建全局的 UI 元素,如模态框、通知框等,而不受组件嵌套结构的限制。
-
卸载和更新: 当 Portal 所在的组件被卸载时,Portal 也会被卸载,并且 Portal 内的状态会被正确地清理。Portal 内容的更新也会被处理,React 会确保内容在目标 DOM 元素上得到正确渲染。
使用
使用 React Portals,需要使用 ReactDOM.createPortal 函数将组件的渲染内容渲染到指定的 DOM 元素上。以下是使用 React Portals 的一般步骤:
- 导入所需的模块: 首先,确保导入了
react和react-dom模块。
import React from 'react';
import ReactDOM from 'react-dom';
- 创建 Portal 组件: 创建一个 React 组件,这个组件将会用于包裹需要渲染的内容。通常,你可以在组件的
render方法中使用ReactDOM.createPortal函数来定义 Portal 的渲染内容以及目标 DOM 元素。
class MyPortal extends React.Component {constructor(props) {super(props);// 创建一个新的 DOM 元素用于 Portalthis.portalElement = document.createElement('div');// 定义要渲染到 Portal 上的内容this.portalContent = (<div><p>这是 Portal 中的内容</p></div>);}componentDidMount() {// 将 Portal 内容渲染到指定的 DOM 元素上document.body.appendChild(this.portalElement);this.componentDidUpdate();}componentDidUpdate() {// 使用 ReactDOM.createPortal 将内容渲染到 Portal 上ReactDOM.createPortal(this.portalContent, this.portalElement);}componentWillUnmount() {// 在组件卸载时,清理 Portaldocument.body.removeChild(this.portalElement);}render() {// 不需要在组件的 render 方法中返回任何内容return null;}
}
- 在应用中使用 Portal 组件: 在你的应用中,可以像使用普通的 React 组件一样使用 Portal 组件,并将其放置在组件树的合适位置。
function App() {return (<div><h1>我的应用</h1><MyPortal /></div>);
}ReactDOM.render(<App />, document.getElementById('root'));
在这个示例中,MyPortal 组件创建了一个 Portal,并将其内容渲染到了 document.body 中的新元素上。可以将 Portal 放置在任何组件中,不受组件层次结构的限制。
注意事项
在使用 React Portals 时,有一些注意事项和最佳实践需要考虑:
-
合适的目标容器: 确保选择一个合适的 DOM 元素作为 Portal 的目标容器。通常,你会在组件的
componentDidMount生命周期方法中将 Portal 添加到 DOM,而在componentWillUnmount中将其移除。 -
避免滥用: 虽然 React Portals 提供了灵活性,但不应滥用它们。只有在必要的情况下使用 Portal,避免过度复杂的嵌套结构。
-
层叠上下文: Portal 可能会破坏默认的 CSS 层叠上下文。如果你的 Portal 内容和其他元素有层叠关系,可能需要手动管理 z-index 或使用 CSS 属性来控制渲染顺序。
-
事件处理: 由于 Portal 的内容可以渲染在组件树之外,因此事件处理可能会受到限制。确保事件处理程序适用于 Portal 内容,或者使用事件冒泡机制。
假设有一个应用,其中包含一个按钮,当点击按钮时,应该显示一个模态框(使用 Portal 渲染)。组件可能如下所示:
import React, { useState } from 'react';
import ReactDOM from 'react-dom';function Modal(props) {const { onClose } = props;return ReactDOM.createPortal(<div className="modal"><div className="modal-content"><p>这是模态框内容。</p><button onClick={onClose}>关闭</button></div></div>,document.getElementById('modal-root'));
}function App() {const [modalOpen, setModalOpen] = useState(false);const openModal = () => {setModalOpen(true);};const closeModal = () => {setModalOpen(false);};return (<div><h1>一个例子</h1><button onClick={openModal}>打开模态框</button>{modalOpen && <Modal onClose={closeModal} />}</div>);
}ReactDOM.render(<App />, document.getElementById('root'));
在上面的示例中,模态框的内容是使用 Portal 渲染的,而 Portal 的目标容器是具有 id="modal-root" 的 DOM 元素。
问题: 模态框中有一个 “关闭” 按钮,但当你点击它时,事件处理程序可能会受到限制,因为模态框渲染在组件树之外。
解决方法: 为了确保事件能够正确地触发和处理,你可以使用事件冒泡机制。在这个示例中,你可以在 “关闭” 按钮上添加事件处理程序,当点击按钮时,事件会冒泡到 DOM 树中,然后在组件树中的父组件中进行处理。
function Modal(props) {const { onClose } = props;return ReactDOM.createPortal(<div className="modal"><div className="modal-content"><p>这是模态框内容。</p><button onClick={onClose}>关闭</button></div></div>,document.getElementById('modal-root'));
}
在上述示例中,当点击模态框中的 “关闭” 按钮时,事件会冒泡回到包含模态框的组件(即 App 组件),然后在 App 组件中的 closeModal`处理函数中进行处理。
-
样式隔离: Portal 可能会引入样式隔离的问题。确保 Portal 内容的样式不会干扰到应用中的其他组件,可以使用 CSS Modules 或其他样式隔离方法。
-
性能考虑: Portal 可能会影响性能,因为它需要将内容渲染到不同的 DOM 元素上。在性能敏感的情况下,需要小心使用 Portal,确保不会导致性能问题。
-
跨浏览器兼容性: Portal 在不同浏览器上的行为可能有所不同。在使用 Portal 时,要测试和验证在各种主流浏览器中的表现。
相关文章:
React Portals
什么是React Portals React Portals(React 门户)是 React 提供的一种机制,用于将组件渲染到 DOM 树中的不同位置,而不受组件层次结构的限制。它允许你将一个组件的渲染内容“传送”到 DOM 结构中的任何位置,通常用于处…...
Python基础之高级函数
异常捕获 Python中,使用trycatch两个关键字来实现对异常的处理。在我们平时的工作中,异常的出现是在所难免的,但是异常一旦出现,极有可能会直接导致程序崩溃,无法正常运行,所以异常一定要及时的做出对应的…...
CSS3常用的新功能总结
CSS3常用的新功能包括圆角、阴渐变、2D变换、3D旋转、动画、viewpor和媒体查询。 圆角、阴影 border-redius 对一个元素实现圆角效果,是通过border-redius完成的。属性为两种方式: 一个属性值,表示设置所有四个角的半径为相同值ÿ…...
Lvs+KeepAlived高可用高性能负载均衡
目录 1.环境介绍 2.配置keepalived 3.测试 1.测试负载均衡 2.测试RS高可用 3.测试LVS高可用 3.1测试lvs主服务宕机 3.2.测试lvs主服务器恢复 4.我在实验中遇到的错误 1.环境介绍 环境:centos7 RS1---RIP1:192.168.163.145 VIP 192.168.163.200 RS2---RIP2…...
无涯教程-Android Online Test函数
Android在线测试模拟了真正的在线认证考试。您将看到基于 Android概念的多项选择题(MCQ),将为您提供四个options。您将为该问题选择最合适的答案,然后继续进行下一个问题,而不会浪费时间。完成完整的考试后,您将获得在线考试分数。 总问题数-20 最长时间-20分钟 Start Test …...
蓝桥杯打卡Day1
文章目录 全排列八皇后 一、全排列IO链接 本题思路:本题是一道经典的全排列问题,深度优先搜索即可解决。 #include <bits/stdc.h>constexpr int N10;std::string s; std::string ans; int n; bool st[N];void dfs(int u) {if(un){std::cout<<ans<…...
zipkin2.24.2源码install遇见的问题
1、idea导入项目后将Setting中的关于Maven和Java Compile相关的配置改为jdk11,同时Project Structure改为jdk11 2、将pom配置中的fork标签注释 标题未修改以上配置产生的问题 Compilation failure javac: Ч ı : --release : javac <options> <source files&g…...
yapi密码是如何生成的
yapi密码是如何生成的 关闭yapi注册功能后,想要通过手动插入用户数据到db中,那么密码是如何生成的呢? exports.generatePassword (password, passsalt) > { return sha1(password sha1(passsalt)); }; 所以如果想要创建一个用户&#x…...
2023-09-02 LeetCode每日一题(最多可以摧毁的敌人城堡数目)
2023-09-02每日一题 一、题目编号 2511. 最多可以摧毁的敌人城堡数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 n ,下标从 0 开始的整数数组 forts ,表示一些城堡。forts[i] 可以是 -1 ,0 或者 1 ,其中&…...
k8s环境部署配置
目录 一.虚拟机准备 二.基础环境配置(各个节点都做) 1.IP和hosts解析 2.防火墙和selinux 3.安装基本软件 4.配置时间同步 5.禁用swap分区 6.修改内核参数并重载 7.配置ipvs 三.docker环境(各个节点都做) 1.配置软件源并…...
Java之文件操作与IO
目录 一.认识文件 1.1文件是什么? 1.2文件的组织 1.3文件路径 1.4文件的分类 二.文件操作 2.1File概述 三.文件内容操作--IO 3.1JavaIO的认识 3.2Reader和Writer ⭐Reader类 ⭐Writer类 3.2FileInputStream和FileOutputStream ⭐FileInputStream类 …...
指令系统(408)
一、拓展操作码指令格式 【2017 统考】某计算机按字节编址,指令字长固定且只有两种指令格式,其中三地址指令29条、二地址指令107条,每个地址字段6位,则指令字长至少应该是( A) A、24位 B、26位 …...
Pygame中Trivia游戏解析6-3
3.3 Trivia类的show_question()函数 Trivia类的show_question()函数的作用是显示题目。主要包括显示题目框架、显示题目内容和显示题目选项等三部分。 3.3.1 显示题目的框架 在show_question()函数中,通过以下代码显示题目的框架。 print_text(font1, 210, 5, &q…...
热释电矢量传感器设计
1 概述 使用4个热释电传感器组成一个2X2的矩阵。通过曲线的相位差、 峰峰值等特征量来计算相关信息。本文使用STM32单片机设计、制作了热释电传感器矩阵;使用C#.NET设计了上位机软件。为以上研究做了试验平台。 2 硬件电路设计 2.1 热释电传感器介绍 热释电红外…...
MySql学习笔记10——视图介绍
视图 概述 view view可以看作是一张“虚拟表”,(但是他也是会作为文件存在的) 当我们通过复杂的查询语句获取一张表的时候,可以将这张表作为一个视图,和创建一个新表不同,在视图上进行的DML操作会对数据…...
【探索Linux】—— 强大的命令行工具 P.7(进程 · 进程的概念)
阅读导航 前言一、冯诺依曼体系结构二、操作系统(OS)1. 概念 三、进程1. 进程的概念2. PCB(Process Control Block)3. 查看进程 四、fork函数1. 函数简介2. 调用方式3. 返回值4. 使用示例 五、进程的几种状态1. 状态简介2. 进程状…...
JAVA宝典----容器(理解记忆)
目录 一、Java Collections框架是什么? 二、什么是迭代器? 三、Iterator与ListIterator有什么区别? 四、ArrayList、Vector和LinkedList有什么区别? 五、HashMap、Hashtable、TreeMap和WeakHashMap有哪些区别? 六…...
JS中的扩展操作符...(点点点)
标题 前言概述拓展操作符(Spread Operator)赋值与扩展操作符的区别 剩余操作符(Rest Operator) 前言 大家应该都在代码中用过或者看到…方法,我每次用到这个方法的时候都会想到第一次见到这个方法一头雾水的样子&#…...
找redis大key工具rdb_bigkeys
github官网 https://github.com/weiyanwei412/rdb_bigkeys 在centos下安装go [roothadoop102 rdb_bigkeys-master]# wget https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz [roothadoop102 rdb_bigkeys-master]# tar -zxf go1.13.5.linux-amd64.tar.gz -C /usr/local将g…...
ElasticSearch进阶
一、 search检索文档 ES支持两种基本方式检索; 通过REST request uri 发送搜索参数 (uri 检索参数);通过REST request body 来发送它们(uri请求体); 1、信息检索 API: https://w…...
Phi-3-mini-4k-instruct-gguf详细步骤:模型升级路径与q4/q5_k_m量化对比测试
Phi-3-mini-4k-instruct-gguf详细步骤:模型升级路径与q4/q5_k_m量化对比测试 1. 模型概述与使用场景 Phi-3-mini-4k-instruct-gguf是微软Phi-3系列中的轻量级文本生成模型GGUF版本,特别适合以下应用场景: 智能问答系统文本改写与润色内容摘…...
电视盒子播放卡顿?教你一招解决所有格式难题
电视盒子播放卡顿?教你一招解决所有格式难题 【免费下载链接】TVBoxOSC TVBoxOSC - 一个基于第三方项目的代码库,用于电视盒子的控制和管理。 项目地址: https://gitcode.com/GitHub_Trending/tv/TVBoxOSC 一、破解家庭娱乐的格式困局 你是否也曾…...
从‘它怎么又挂了’到‘服务稳如狗’:我是如何用Prometheus+Grafana搭建业务监控看板的
从被动救火到主动防御:PrometheusGrafana构建业务监控实战手册 凌晨三点,手机突然响起刺耳的警报声——这已经是本周第三次了。揉着惺忪的睡眼查看日志,却发现关键线索早已被淹没在海量的调试信息中。这样的场景对于中小技术团队来说再熟悉不…...
如何通过ExplorerPatcher实现Windows 11界面个性化定制:从经典布局到高效工作流
如何通过ExplorerPatcher实现Windows 11界面个性化定制:从经典布局到高效工作流 【免费下载链接】ExplorerPatcher This project aims to enhance the working environment on Windows 项目地址: https://gitcode.com/GitHub_Trending/ex/ExplorerPatcher Wi…...
Mid-70激光雷达与相机无目标标定:从环境搭建到实战避坑
1. 为什么选择Ubuntu 16.04进行Mid-70标定 最近在给Livox Mid-70激光雷达做相机标定时,我踩了个大坑——在Ubuntu 22.04上折腾了整整两天都没搞定环境配置。后来才发现问题出在版本兼容性上:ROS Kinetic、Ceres 1.14.x和Eigen 3.2.92这几个关键组件在新系…...
从v4l2-ctl命令到media拓扑:手把手教你调试RK3568上的OV8858摄像头图像
RK3568平台OV8858摄像头深度调试实战:从硬件链路到图像优化的全流程解析 当你在RK3568平台上调试OV8858摄像头时,是否遇到过这样的场景:设备树配置看似正确,但摄像头输出的图像却出现花屏、颜色异常或干脆没有信号?作为…...
【ROS2 基础】ROS2与Colcon核心指令速查手册与避坑指南
为了在 ROS2 的日常开发中提升效率,本文为您整理了一份结构化的核心指令速查清单。去除了冗长的理论,直击实战痛点,并附带了多平台差异、性能优化数据以及常见报错的修复方案。 文章目录[TOC]一、 快速入门:3步跑通基础流程二、 版…...
避坑指南:QT5的QListView复选框居中/对齐问题解决方案(含TableView对比)
QT5复选框对齐终极指南:从QListView到TableView的完美排版方案 在QT5界面开发中,复选框控件的视觉对齐问题堪称"程序员强迫症终结者"——明明功能已经实现,却总在UI细节上栽跟头。本文将带您深入解决QListView和TableView中复选框居…...
卡证检测矫正模型中小企业降本:替代万元级专用证件扫描仪方案
卡证检测矫正模型:中小企业降本利器,替代万元级专用证件扫描仪方案 1. 引言:一个被忽视的降本痛点 如果你在中小企业负责行政、人事或财务,一定对下面这个场景不陌生:每天要处理一堆身份证、护照、驾照的复印件或扫描…...
OpenClaw数据安全:Qwen3.5-4B-Claude本地处理敏感合同
OpenClaw数据安全:Qwen3.5-4B-Claude本地处理敏感合同 1. 为什么法律行业需要本地化AI处理 去年我参与了一个法律科技项目,团队最初尝试用公有云API处理合同文本时,遭遇了客户对数据出海的强烈抵触。某次演示中,当法务总监看到合…...
