文章目錄
- 適合場景
- 基本語法
- 示例:Modal 彈窗
- 1. 創建一個簡單的 Modal.tsx
- 2. 在 App 中使用
- 為什么要用 Portal?
- TypeScript 中 Portal 類型定義?
適合場景
React Portal 是 React 提供的一種機制,讓你可以將子組件渲染到 DOM 的指定節點中,而不是默認的父組件 DOM 層級中。
非常適合:
? 彈窗(Modal)
? Tooltip
? Popover
? 全局消息提示(Toast)等浮層組件的實現
基本語法
import { createPortal } from 'react-dom';const MyPortal = () => {return createPortal(<div>I’m rendered in a portal!</div>,document.getElementById('portal-root')! // 目標容器);
};
你需要確保 HTML 里有這個 DOM 節點:
<!-- index.html -->
<body><div id="root"></div><div id="portal-root"></div>
</body>
示例:Modal 彈窗
1. 創建一個簡單的 Modal.tsx
import React from 'react';
import ReactDOM from 'react-dom';type ModalProps = {visible: boolean;onClose: () => void;children: React.ReactNode;
};const Modal: React.FC<ModalProps> = ({ visible, onClose, children }) => {if (!visible) return null;return ReactDOM.createPortal(<div style={styles.mask}><div style={styles.modal}>{children}<button onClick={onClose}>Close</button></div></div>,document.getElementById('portal-root')!);
};const styles = {mask: {position: 'fixed' as const,top: 0, left: 0, right: 0, bottom: 0,backgroundColor: 'rgba(0, 0, 0, 0.3)',display: 'flex',justifyContent: 'center',alignItems: 'center',},modal: {background: '#fff',padding: 20,borderRadius: 8,minWidth: 300,},
};export default Modal;
2. 在 App 中使用
import React, { useState } from 'react';
import Modal from './Modal';const App = () => {const [visible, setVisible] = useState(false);return (<><button onClick={() => setVisible(true)}>Open Modal</button><Modal visible={visible} onClose={() => setVisible(false)}><h2>This is a Portal Modal</h2></Modal></>);
};export default App;
為什么要用 Portal?
如果你直接把 Modal 放在組件里,它可能被某些 CSS 樣式限制(比如 overflow: hidden
、z-index
),無法正確展示。
Portal 允許你將組件“掛”在 HTML 的任意節點(如根節點外層),避免被父組件樣式影響,同時又保持了 React 的事件機制和數據流。
TypeScript 中 Portal 類型定義?
ReactDOM.createPortal
的類型如下:
createPortal(children: ReactNode,container: Element | DocumentFragment
): ReactPortal
所以你通常會這么寫:
ReactDOM.createPortal(<div>內容</div>,document.getElementById('portal-root')!
);
其中返回值類型是 React.ReactPortal
,它是 ReactNode
的子類型,意味著它可以被正常地渲染。