如何在 React 16 中使用 ReactDOM.createPortal()?

新手上路,请多包涵

我正在使用 React 16 并需要门户网站,但我无法找到有关此功能的任何文档。有谁知道如何使用这个吗?

https://github.com/facebook/react/pull/10675

感谢您的任何建议。

原文由 Slbox 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

React v16 几个小时前刚刚发布(耶!!),正式支持 Portal

什么是门户网站?它在那里多久了?

门户提供了一种一流的方式来将子项呈现到存在于父组件的 DOM 层次结构之外的 DOM 节点中。

Portal 在 React 社区中不是新概念。许多库都支持这种功能。例如 react-portalreact-gateway

渲染任何反应应用程序时会发生什么?

通常,在渲染任何 React 应用程序时,单个 DOM 元素用于渲染整个 React 树。

 class HelloReact extends React.Component {
   render() {
       return (
          <h1>Hello React</h1>
       );
   }
}

ReactDOM.render(<HelloReact />, document.getElementById('root'));

如您所见,我们正在将我们的 React 组件渲染到具有 id root 的 DOM 元素中。

什么是门户网站,为什么需要它?为什么它在那里?

门户是一种在父组件的主要 DOM 层次结构之外渲染 React 子组件 而不丢失 React 上下文的 方法。我之所以强调它,是因为像 react-routerredux 这样非常流行的库大量使用了 react 上下文。因此,使用 Portal 时的上下文可用性非常有帮助。

根据 反应 文档,

门户的一个典型用例是当父组件具有溢出:隐藏或 z-index 样式,但您需要子组件在视觉上“突破”其容器。例如,对话框、悬浮卡片和工具提示。

因此,使用门户,您可以在需要时将并行反应树渲染到另一个 DOM 节点上。即使它在不同的 DOM 节点中呈现,父组件也可以捕获未捕获的事件。请参阅文档本身中提供的此 代码笔

下面的例子应该给你更多的想法:

 // 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

You can use devtools inspect element and see that <h1>I am rendered through a Portal.</h1> is rendered inside #another-root tag, whereas <h1>Hello World</h1> is rendered inside #root tag.

希望这可以帮助 :)

更新:回答 @PhillipMunin 的评论

ReactDOM.renderReactDOM.createPortal 有什么区别?

  1. 即使通过门户呈现的组件在其他地方呈现(在当前容器根之外),它仍然作为同一父组件的子组件存在。 (谁调用了 ReactDOM.createPortal )所以关于孩子的任何事件都会传播到父母。 (Ofc,如果您手动停止事件的传播,这将不起作用。)

  2. 通过门户呈现的组件内部可以访问相同的上下文。但不是在我们直接执行 ReactDOM.render 的情况下。

我创建了另一个演示来说明我的观点。 https://codesandbox.io/s/42x771ykwx

原文由 Hardik Modha 发布,翻译遵循 CC BY-SA 3.0 许可协议

我认为我们可以通过在“root”元素之外创建一个外部 dom 节点来实现相同的功能

node = document.createElement('div')
document.body.appendChild(node)
ReactDOM.render(<Modal {...props} />,node)

假设我们正在创建一个模态视图,我们可以为它创建一个包装器

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 />
    )
}

这是一个 使用 React Portal 和 React Hooks 在没有外部库的情况下从头开始创建模式 的示例

带有门户的 React-modal

原文由 OnlyJS 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题