Render React element
1. React DOM 與 root
React 使用 ReactDOM 來將 React 元件渲染到瀏覽器的 DOM 樹中。在 React 18 中,引入了 createRoot API,取代舊的 ReactDOM.render 方法,用於創建一個"根節點"(root),作為 React 管理的入口點。這個根節點會綁定到 HTML 中的某個元素(通常是一個 <div>
),React 會在這個容器內管理所有的渲染和更新。
- 關鍵點:
- 使用 ReactDOM.createRoot 創建根節點,並指定 DOM 容器(例如
<div id="root">
)。 - 透過 root.render() 方法將 React 元件渲染到指定的 DOM 節點。
- 這是 React 與瀏覽器 DOM 交互的核心方式。
- 使用 ReactDOM.createRoot 創建根節點,並指定 DOM 容器(例如
2. React 只會操作真正需要更新的 DOM 元素
React 的核心優勢之一是高效的 DOM 更新機制,透過 Virtual DOM 實現。當狀態(state)或屬性(props)改變時,React 會比較新舊 Virtual DOM,找出需要更新的部分(差異化更新,diffing),然後只更新實際改變的 DOM 節點,而不是重新渲染整個頁面。
- 關鍵點:
- React 使用"調和"(reconciliation)過程來決定哪些 DOM 元素需要更新。
- 如果某個元件的狀態或屬性沒有改變,React 不會重新渲染該部分的 DOM。
- 這大幅提高了效能,尤其是在複雜的應用程式中。
3. 瀏覽器環境以外的 React 畫面繪製
React 不僅限於瀏覽器環境,也可以應用在其他環境,例如伺服器端渲染(SSR)或靜態網站生成(SSG)。這通常透過 ReactDOMServer 實現,允許在 Node.js 環境中將 React 元件渲染為 HTML 字串。此外,React Native 也是一個例子,展示了 React 如何在非瀏覽器環境(例如行動應用程式)中繪製畫面。
- 關鍵點:
- 伺服器端渲染:使用 ReactDOMServer.renderToString 或 renderToStaticMarkup 生成 HTML,適用於 SEO 或提升首屏載入速度。
- React Native:React 的元件邏輯可以用於渲染原生行動應用程式的 UI 元素,而非 DOM。
- 這些技術讓 React 的元件邏輯可以跨平台重用。
程式碼範例
以下是一個完整的 React 範例,展示上述三個概念。這個範例包含一個計數器應用程式,模擬 React DOM 的渲染,只更新必要的 DOM 元素,並附上伺服器端渲染的簡單展示。
檔案結構
假設你有一個簡單的專案結構:
project/
├── index.html
├── App.js
├── server.js
1. index.html(客戶端渲染)
這個檔案展示 React DOM 與 root 的使用,並包含一個計數器元件來展示 DOM 的差異化更新。
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React DOM 與更新範例</title>
<!-- 引入 React 和 ReactDOM 的 CDN -->
<script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.development.js"></script>
<!-- 引入 Babel 用於轉譯 JSX -->
<script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.22.5/Babel.min.js"></script>
<!-- 引入 Tailwind CSS 進行簡單樣式設計 -->
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<!-- 定義 root 容器 -->
<div
id="root"
class="min-h-screen bg-gray-100 flex items-center justify-center"
></div>
<script type="text/babel">
// 定義計數器元件
function Counter() {
// 使用 useState 管理計數器狀態
const [count, setCount] = React.useState(0);
// 定義一個靜態文字,模擬不變的內容
const [staticText] = React.useState("這段文字不會改變");
// 點擊按鈕時更新計數
const handleClick = () => {
setCount((prevCount) => prevCount + 1);
};
// 2 React 只會更新必要的 DOM 元素
// 當 count 改變時,只有 <p> 標籤中的計數部分會更新
// staticText 因為未改變,React 不會重新渲染這部分的 DOM
return (
<div className="p-6 bg-white rounded-lg shadow-lg text-center">
<h1 className="text-2xl font-bold mb-4">React DOM 更新範例</h1>
<p className="text-lg mb-4">{staticText}</p>
<p className="text-lg mb-4">計數: {count}</p>
<button
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
onClick={handleClick}
>
增加計數
</button>
</div>
);
}
// 1 React DOM 與 root
// 使用 createRoot 創建 React 的根節點,綁定到 id="root" 的 DOM 元素
const root = ReactDOM.createRoot(document.getElementById("root"));
// 將 Counter 元件渲染到 root
root.render(<Counter />);
</script>
</body>
</html>
2. App.js(共用元件 - 使用 ES 模組格式)
這個檔案定義了計數器元件,供客戶端和伺服器端共用。使用 ES 模組格式。
import React from "react";
function Counter() {
const [count, setCount] = React.useState(0);
const [staticText] = React.useState("這段文字不會改變");
const handleClick = () => {
setCount((prevCount) => prevCount + 1);
};
return (
<div className="p-6 bg-white rounded-lg shadow-lg text-center">
<h1 className="text-2xl font-bold mb-4">React DOM 更新範例</h1>
<p className="text-lg mb-4">{staticText}</p>
<p className="text-lg mb-4">計數: {count}</p>
<button
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
onClick={handleClick}
>
增加計數
</button>
</div>
);
}
export default Counter;
3. server.js(伺服器端渲染範例)
這個檔案展示如何在 Node.js 環境中使用 ReactDOMServer 渲染 React 元件為 HTML 字串,模擬非瀏覽器環境的畫面繪製。
import express from "express";
import React from "react";
import ReactDOMServer from "react-dom/server";
import Counter from "./App.js"; // 引入共用的 Counter 元件
const app = express();
// 定義路由,渲染 Counter 元件為 HTML
app.get("/", (req, res) => {
// 3 瀏覽器環境以外的 React 畫面繪製
// 使用 renderToString 將 React 元件轉為 HTML 字串
const html = ReactDOMServer.renderToString(React.createElement(Counter));
// 將生成的 HTML 包裝在完整的頁面中
const page = `
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>伺服器端渲染範例</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="root">${html}</div>
</body>
</html>
`;
res.send(page);
});
// 啟動伺服器
app.listen(3000, () => {
console.log("伺服器運行在 http://localhost:3000");
});
程式碼如何對應三個主題
-
React DOM 與 root:
- 在 index.html 中,ReactDOM.createRoot 創建了根節點,綁定到
<div id="root">
。 root.render(<Counter />)
將元件渲染到 DOM,展示了 React 如何管理 DOM 樹。
- 在 index.html 中,ReactDOM.createRoot 創建了根節點,綁定到
-
React 只會操作真正需要更新的 DOM 元素:
- 在 Counter 元件中,count 狀態改變時,只有
<p>計數: {count}</p>
會更新。 - staticText 的值保持不變,React 不會重新渲染這部分的 DOM,體現了高效的更新機制。
- 在 Counter 元件中,count 狀態改變時,只有
-
瀏覽器環境以外的 React 畫面繪製:
- 在 server.js 中,ReactDOMServer.renderToString 將 Counter 元件渲染為 HTML 字串,模擬伺服器端渲染。
- 這展示了 React 如何在非瀏覽器環境中生成畫面內容,適用於 SEO 或靜態網站生成。