说说你对react中 createPortal 的了解?

872 阅读3分钟

基本概念

ReactDOM.createPortal 是 React 提供的一个 API,用于将子组件渲染到 DOM 树中的任意位置,而不是当前组件的父组件层级中。这在某些场景下非常有用,比如处理模态框(Modal)、工具提示(Tooltip)、通知(Notification)等需要脱离当前组件层级的情况。


1. 基本用法

createPortal 的语法如下:

ReactDOM.createPortal(child, container);
  • child: 需要渲染的 React 子元素(可以是组件、JSX 等)。
  • container: 目标 DOM 节点,child 会被渲染到这个节点中。

2. 使用场景

createPortal 的主要用途是将组件渲染到 DOM 树的其他位置,同时保持组件在 React 组件树中的逻辑关系。常见的场景包括:

(1)模态框(Modal)

模态框通常需要覆盖整个页面,并且脱离当前组件的 DOM 层级。使用 createPortal 可以将模态框渲染到 <body> 或其他容器中。

import React from 'react';
import ReactDOM from 'react-dom';

function Modal({ children }) {
  return ReactDOM.createPortal(
    <div className="modal">
      {children}
    </div>,
    document.body // 渲染到 body 中
  );
}

function App() {
  return (
    <div>
      <h1>My App</h1>
      <Modal>
        <p>This is a modal!</p>
      </Modal>
    </div>
  );
}

(2)工具提示(Tooltip)

工具提示通常需要脱离当前组件的 DOM 层级,以避免被父组件的样式(如 overflow: hidden)影响。

import React from 'react';
import ReactDOM from 'react-dom';

function Tooltip({ children, target }) {
  return ReactDOM.createPortal(
    <div className="tooltip">
      {children}
    </div>,
    target // 渲染到目标 DOM 节点中
  );
}

(3)通知(Notification)

通知通常需要渲染到页面的顶部或底部,脱离当前组件的 DOM 层级。


3. 特点

  • 保持 React 组件树的逻辑关系
    虽然 createPortal 将组件渲染到 DOM 树的其他位置,但组件在 React 组件树中的逻辑关系保持不变。事件冒泡和上下文(Context)仍然会按照 React 组件树的层级传递。

  • 适用于脱离当前 DOM 层级的场景
    当组件的样式或行为需要脱离当前 DOM 层级时,createPortal 是一个很好的解决方案。

  • 不会影响组件的生命周期
    使用 createPortal 渲染的组件仍然会正常触发生命周期方法(如 useEffectcomponentDidMount 等)。


4. 注意事项

  • 确保目标容器存在
    在使用 createPortal 时,目标容器(container)必须已经存在于 DOM 中,否则会报错。

  • 避免滥用
    createPortal 应该用于特定的场景(如模态框、工具提示等),而不是常规的组件渲染。滥用可能会导致代码难以维护。

  • 事件冒泡
    虽然 createPortal 将组件渲染到 DOM 树的其他位置,但事件仍然会按照 React 组件树的层级冒泡。例如,点击模态框中的按钮,事件会冒泡到父组件。


5. 示例代码

以下是一个完整的模态框示例:

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

function Modal({ children, onClose }) {
  return ReactDOM.createPortal(
    <div className="modal-overlay">
      <div className="modal-content">
        {children}
        <button onClick={onClose}>Close</button>
      </div>
    </div>,
    document.body
  );
}

function App() {
  const [isModalOpen, setModalOpen] = useState(false);

  return (
    <div>
      <h1>My App</h1>
      <button onClick={() => setModalOpen(true)}>Open Modal</button>
      {isModalOpen && (
        <Modal onClose={() => setModalOpen(false)}>
          <p>This is a modal!</p>
        </Modal>
      )}
    </div>
  );
}

export default App;

总结

  • ReactDOM.createPortal 用于将组件渲染到 DOM 树中的任意位置。
  • 它适用于模态框、工具提示、通知等需要脱离当前 DOM 层级的场景。
  • 使用 createPortal 时,组件在 React 组件树中的逻辑关系保持不变,事件冒泡和上下文仍然有效。
  • 避免滥用 createPortal,仅在必要时使用。