Javascript 如何在 React 16 中使用 ReactDOM.createPortal()?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46393642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use ReactDOM.createPortal() in React 16?
提问by Slbox
I'm using React 16 and need portals, but am not able to find any documentation on this feature. Does anyone know how to use this yet?
我正在使用 React 16 并需要门户网站,但找不到关于此功能的任何文档。有谁知道如何使用它?
https://github.com/facebook/react/pull/10675
https://github.com/facebook/react/pull/10675
Thanks for any advice.
感谢您的任何建议。
回答by Hardik Modha
React v16 has just released a couple of hours ago (Yay!!) which officially supports Portal.
React v16 几个小时前刚刚发布(耶!!),它正式支持Portal.
What is Portal? Since How long has it been there?
什么是门户?它已经存在多久了?
Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
Portals 提供了一种一流的方式来将子组件渲染到存在于父组件的 DOM 层次结构之外的 DOM 节点中。
Portalis not new concept in the react community. Many libraries are available that supports this kind of functionality. e.g react-portaland react-gateway.
Portal在 React 社区中并不是新概念。许多库都支持这种功能。例如react-portal和react-gateway。
What happens when rendering any react app?
渲染任何反应应用程序时会发生什么?
Generally, when rendering any React application, a single DOM element is used to render the whole React tree.
通常,在渲染任何 React 应用程序时,都会使用单个 DOM 元素来渲染整个 React 树。
class HelloReact extends React.Component {
render() {
return (
<h1>Hello React</h1>
);
}
}
ReactDOM.render(<HelloReact />, document.getElementById('root'));
As you can see we are rendering our react component into a DOM element having id root.
如您所见,我们正在将我们的 react 组件渲染为具有 id 的 DOM 元素root。
What is Portal and why is it needed? Why is it there?
什么是 Portal,为什么需要它?为什么会在那里?
Portals are a way to render React children outside the main DOM hierarchy of the parent component without losing the react context. I'm emphasizing on it because very popular libraries like react-router, reduxheavily uses the react context. So context availability when using Portalis very helpful.
Portals 是一种在父组件的主 DOM 层次结构之外呈现 React 子组件的方法,而不会丢失React上下文。我强调它是因为非常流行的库,如react-router,redux大量使用 react 上下文。所以使用时的上下文可用性Portal非常有帮助。
As per the reactdocs,
根据反应文档,
A typical use case for portals is when a parent component has an overflow: hidden or z-index style, but you need the child to visually "break out" of its container. For example, dialogs, hovercards, and tooltip.
门户的典型用例是父组件具有溢出:隐藏或 z-index 样式,但您需要子组件在视觉上“突破”其容器。例如,对话框、悬停卡和工具提示。
So, with portals, you can render a parallel react tree onto another DOM node when needed. Even though it is rendered in the different DOM node, parent component can catch the uncaught events. See this codepenprovided in the docs itself.
因此,使用门户网站,您可以在需要时将并行反应树渲染到另一个 DOM 节点上。即使它在不同的 DOM 节点中呈现,父组件也可以捕获未捕获的事件。请参阅文档本身中提供的此代码笔。
The below example should give your more idea:
下面的例子应该给你更多的想法:
// index.html
<html>
<body>
<div id="root"></div>
<div id="another-root"></div>
</body>
</html>
// index.jsx
const mainContainer = document.getElementById('root');
const portalContainer = document.getElementById('another-root');
class HelloFromPortal extends React.Component {
render() {
return (
<h1>I am rendered through a Portal.</h1>
);
}
}
class HelloReact extends React.Component {
render() {
return (
<div>
<h1>Hello World</h1>
{ ReactDOM.createPortal(<HelloFromPortal />, portalContainer) }
</div>
);
}
}
ReactDOM.render(<HelloReact />, mainContainer);
https://codesandbox.io/s/62rvxkonnw
https://codesandbox.io/s/62rvxkonnw
You can use devtools inspect element and see that <h1>I am rendered through a Portal.</h1>is rendered inside #another-roottag, whereas <h1>Hello World</h1>is rendered inside #roottag.
您可以使用 devtools 检查元素并查看它<h1>I am rendered through a Portal.</h1>在#another-root标签内部呈现,而<h1>Hello World</h1>在#root标签内部呈现。
Hope this helps :)
希望这可以帮助 :)
Update: To answer @PhillipMunin's comment.
更新:回答@PhillipMunin 的评论。
What is the different between
ReactDOM.renderandReactDOM.createPortal?
ReactDOM.render和 之间有什么区别ReactDOM.createPortal?
Even though the component rendered through the portal is rendered somewhere else (Outside the current container root), it remains present as the child of the same parent component. (Who invoked the
ReactDOM.createPortal) So any events on the child are propagated to the parent. (Ofc, This doesn't work if you manually stop the propagation of the event.)Same context is accessible inside the component rendered through a portal. But not in the case when we do
ReactDOM.renderdirectly.
即使通过门户呈现的组件在其他地方呈现(在当前容器根之外),它仍然作为同一父组件的子组件存在。(谁调用了
ReactDOM.createPortal)因此子级上的任何事件都会传播到父级。(Ofc,如果您手动停止事件的传播,这将不起作用。)在通过门户呈现的组件内部可以访问相同的上下文。但不是在我们
ReactDOM.render直接做的情况下。
I've created another demo to illustrate my point. https://codesandbox.io/s/42x771ykwx
我创建了另一个演示来说明我的观点。https://codesandbox.io/s/42x771ykwx
回答by OnlyJS
I think we can achieve same feature by creating an external dom node outside 'root' element
我认为我们可以通过在“root”元素之外创建一个外部 dom 节点来实现相同的功能
node = document.createElement('div')
document.body.appendChild(node)
ReactDOM.render(<Modal {...props} />,node)
Let's say we are creating a modal view, we can create a wrapper for the same
假设我们正在创建一个模态视图,我们可以为它创建一个包装器
import React, { useEffect } from 'react'
import ReactDOM from 'react-dom'
import Modal from './Modal'
let node = null
const ModalWrapper = (props) =>{
useEffect(()=>{
node && ReactDOM.render(<Modal {...props} />,node)
})
useEffect(()=>{
node = document.createElement('div')
document.body.appendChild(node)
ReactDOM.render(<Modal {...props} />,node)
},[])
return(
<script />
)
}
Here is an example Create Modal with React Portal and React Hooks from scratch without external library
回答by Marko
Portals are created by calling the createPortalmethod inside the rendermethod of your component.
门户是通过调用组件createPortal方法内部的render方法创建的。
render() {
return (
<div>
{ReactDOM.createPortal(this.renderPortal(), this.props.portalEl)}
</div>
)
}
renderPortalshould return contents to be rendered inside the portal, while portalElis an external DOM element that will receive the content.
renderPortal应该返回要在门户内部呈现的内容,而portalEl是将接收内容的外部 DOM 元素。
Someone recently twitted that info on portals can be found in React tests.
最近有人发推说,可以在React 测试中找到有关门户的信息。
回答by devaent
For anyone wondering, here is how I implemented my own custom Portal component in Typescript
对于任何想知道的人,这是我如何在 Typescript 中实现我自己的自定义 Portal 组件
import React from 'react'
import ReactDOM from 'react-dom'
const Portal: React.FC<PortalProps> = (props) => {
return ReactDOM.createPortal(props.children, props.target)
}
export interface PortalProps {
target: Element;
children: React.ReactNode;
}
export default Portal


