React Fragments 與 Portals
React Fragments 與 Portals
在 React 開發中,Fragments 和 Portals 是兩個有助於控制 DOM 結構的強大工具。Fragments 允許在不增加額外 DOM 節點的情況下返回多個元素,而 Portals 則可以讓你將組件的子元素渲染到 DOM 樹中的不同位置。
1. Fragments (片段)
1.1 什麼是 Fragment?
在 React 中,一個組件的 render
方法或函數組件只能返回一個單一的 DOM 節點。然而,當我們希望返回多個元素而不希望額外的包裹元素影響 DOM 結構時,可以使用 Fragment 來包裹這些元素。Fragments 本身不會在 DOM 中創建任何多餘的節點。
1.2 基本語法
使用 React.Fragment
或其簡寫 <></>
,可以在不增加多餘的 DOM 標籤的情況下返回多個子元素。
1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
function MyComponent() {
return (
<React.Fragment>
<h1>標題</h1>
<p>這是一段文字。</p>
</React.Fragment>
);
}
export default MyComponent;
簡寫形式:
1
2
3
4
5
6
7
8
function MyComponent() {
return (
<>
<h1>標題</h1>
<p>這是一段文字。</p>
</>
);
}
1.3 使用場景
避免多餘的包裹元素:在不需要額外 DOM 節點的情況下組織多個元素,避免引入不必要的
<div>
或其他包裹元素。提升渲染性能:因為 Fragment 不會創建額外的 DOM 節點,它有助於優化渲染性能,特別是在需要渲染大量元素時。
2. Portals (入口)
2.1 什麼是 Portal?
React Portals 提供了一個將子元素渲染到父組件 DOM 節點之外的方式。換句話說,Portal 允許你將組件的部分 UI 渲染到 DOM 樹中的另一個節點,而不是按照 React 組件層次結構進行渲染。
2.2 基本語法
Portals 使用 ReactDOM.createPortal
來實現,它接受兩個參數:
- 子元素:你想要渲染的子組件。
- DOM 節點:目標 DOM 節點,即你希望渲染到的位置。
1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import ReactDOM from 'react-dom';
function MyPortalComponent() {
return ReactDOM.createPortal(
<div>這是從 Portal 渲染出來的內容。</div>,
document.getElementById('portal-root') // 指定渲染位置
);
}
export default MyPortalComponent;
在上例中,我們將一個 div
元素渲染到了具有 id="portal-root"
的 DOM 節點中,這個節點可能與 React 應用的根節點是平行的。
2.3 使用場景
模態窗口 (Modal):模態窗口通常需要渲染在頂層,脫離當前組件的 DOM 層次結構。使用 Portals 可以確保模態窗口不會受到父組件的
overflow
或z-index
的影響。工具提示 (Tooltip):像 Tooltip 這樣的浮動 UI 元素,也經常需要在 DOM 的特殊位置渲染,以避免被其他元素遮蓋。
全局通知或對話框:這些元素經常需要渲染在應用的最外層,使用 Portals 可以更容易管理它們。
2.4 範例:模態窗口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
<div className="modal">
<div className="modal-content">
{children}
</div>
</div>,
document.getElementById('modal-root')
);
}
function App() {
const [showModal, setShowModal] = useState(false);
const handleToggleModal = () => {
setShowModal(!showModal);
};
return (
<div>
<button onClick={handleToggleModal}>
{showModal ? '隱藏模態窗口' : '顯示模態窗口'}
</button>
{showModal && <Modal>這是一個模態窗口</Modal>}
</div>
);
}
export default App;
在這個範例中,我們使用 Portal 將模態窗口渲染到了 id="modal-root"
的 DOM 節點中,這樣即使它在父組件之外,它也能正確地顯示和運行。
3. Fragments 與 Portals 的區別
- Fragments:用於組織 JSX 結構,在不引入多餘 DOM 節點的情況下返回多個元素,從而保持 DOM 結構的簡潔。
- Portals:用於將子元素渲染到不同於父組件 DOM 結構的節點,適合處理模態窗口、浮動 UI 等需要脫離組件層次的元素。
4. 總結
- Fragments 使你可以返回多個元素而不引入額外的 DOM 節點,適合在不需要包裹的情況下渲染多個子元素。
- Portals 讓你可以將子組件渲染到父組件之外的 DOM 節點,這對於模態窗口、工具提示等需要脫離常規 DOM 結構的情況非常有用。
使用 Fragments 和 Portals 可以幫助你靈活管理應用中的 DOM 結構,同時提高性能和靈活性。