React Portal 案例学习
Posted GoldenaArcher
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Portal 案例学习相关的知识,希望对你有一定的参考价值。
React Portal 案例学习
最近看文档/教程/资料,偶然间看到了一个以前没有碰到的东西:Portal。本着学习的精神打开了文档一看,才发现 Portal 的存在真的解决了一些以前碰到的问题。
什么是 Portal
Portal 是 ReactDOM 在 v16 的时候新推出的一个特性,到目前来说已经有 5 年的特性。它的优点有这几个:
- 可以在虚拟 DOM 树之外挂载 React 结点
- 挂在的 React 结点虽然物理地址在虚拟 DOM 树之外,但是其父组件可以监听到该组件的事件冒泡
- React Context 可以完整地保留
使用 Portal
官方文档上举例 Portal 的应用场景,包括:dialogs(对话框), hovercards(悬浮卡片), and tooltips(提示工具)。
下面就是一个 Modal 的简单的案例。
import "./styles.css";
const Modal = () =>
return <div className="modal">Modal</div>;
;
export default function App()
return (
<div className="App">
<div className="modal__wrapper">
<Modal />
</div>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<h3>What happen here</h3>
<h4>something happen here</h4>
</div>
);
其渲染结果如下:
基本上可以满足我的需求。
但是,有的时候业务逻辑是需要在组件中进行条件渲染,这个时候 Modal 的定位可能就会出现问题,如:
以及
诚然,再创建一个新的 backdrop,定位高度宽度为 100vh,让其背景色为透明, position 设置为 relative,再继续使用 CSS 对 Modal 进行位置的调控也能暴力解决问题(惭愧……这就是之前我为了快速推进度而采取的解决方法)。不过这样粗暴的解决方法也有一定的问题:
-
用户不关闭当前 Modal 之前是无法与背景上的元素进行任何的交互
-
语义化的结构也不对
这个时候,使用 Portal 就可以解决这个问题,如:
对 div 进行位置上的改变:
渲染效果还是完全一样的。
这是因为 Portal 被挂载的元素在元素 id 为 modal 的结点上,而 modal 所处的位置在:
<body>
<noscript> You need to enable javascript to run this app. </noscript>
<div id="modal"></div>
<div id="root"></div>
</body>
对渲染的 html 结果进行分析,也会发现 Modal 组件被挂载到了 #modal
结点上:
事件冒泡
现在将代码少许更新一下:
import "./styles.css";
import ReactDOM from "react-dom";
const Modal = ( clickHandler ) =>
return (
<div className="modal">
<button onClick=clickHandler>btn</button>
</div>
);
;
export default function App()
const clickHandler = () =>
console.log("hello world");
;
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<h3>What happen here</h3>
<h4>something happen here</h4>
<div className="modal__wrapper">
ReactDOM.createPortal(
<Modal clickHandler=clickHandler />,
document.querySelector("#modal")
)
</div>
</div>
);
这里也模拟了一些使用 Modal 会经常碰到的情况,也就是事件处理。在使用 Portal 的情况下,App
这个父组件是可以将事件处理函数传送到 Modal 中:
同样的情况下,onChange 之类的事件监听也是可以触发,从而修改父组件中的状态,或是复用父组件中的事件处理函数。
Context 的使用
我会加上这一点其实是因为这个 Stack Overflow 的回答:How to use ReactDOM.createPortal() in React 16?,其中得分最高的回复人说到:
I’m emphasizing on it because very popular libraries like react-router, redux heavily uses the react context. So context availability when using
Portal
is very helpful.
如 react-router, redux 的第三方库是 React Context 的重度依赖者,因此想要最大程度地享用这些库的特性,也需要保留 React Context 的内容。
参考资料
以上是关于React Portal 案例学习的主要内容,如果未能解决你的问题,请参考以下文章