React 入門
在本文中,我們將向 React 問好。我們將詳細瞭解它的背景和用例,在本地計算機上設定基本的 React 工具鏈,並建立一個簡單的入門應用程式並進行試用——在此過程中學習 React 的工作原理。
| 預備知識 | 熟悉核心 HTML、CSS 和 JavaScript 語言,以及 終端/命令列。 |
|---|---|
| 學習成果 | 設定本地 React 開發環境,建立啟動應用程式,並瞭解其工作原理的基礎知識。 |
你好 React
正如其官方標語所述,React 是一個用於構建使用者介面的庫。React 不是一個框架——它甚至不侷限於 Web。它與其他庫一起用於渲染到特定環境。例如,React Native 可用於構建移動應用程式。
為了進行 Web 開發,開發人員將 React 與 ReactDOM 結合使用。React 和 ReactDOM 經常在相同的領域被討論——並用於解決與其他真正的 Web 開發框架相同的問題。當我們把 React 稱為“框架”時,我們是按照這種口語化的理解來使用的。
React 的主要目標是最大限度地減少開發人員構建 UI 時發生的錯誤。它透過使用元件來做到這一點——元件是自包含的、邏輯性的程式碼片段,描述了使用者介面的一個部分。這些元件可以組合在一起建立完整的 UI,React 抽象了大部分渲染工作,讓你專注於 UI 設計。
用例
與本模組中介紹的其他框架不同,React 不強制執行嚴格的程式碼約定或檔案組織規則。這允許團隊設定最適合他們的約定,並以他們希望的任何方式採用 React。React 可以處理一個按鈕、介面的一些片段或應用程式的整個使用者介面。
雖然 React 可以用於 介面的一小部分,但它不像 jQuery 等庫,甚至 Vue 等框架那樣容易“放入”應用程式——當你用 React 構建整個應用程式時,它更容易上手。
此外,React 應用程式的許多開發者體驗優勢,例如使用 JSX 編寫介面,都需要編譯過程。向網站新增 Babel 等編譯器會使程式碼執行緩慢,因此開發人員通常會透過構建步驟來設定此類工具。React 可以說有很高的工具要求,但它是可以學習的。
本文將重點介紹使用 React 結合 Vite(一個現代前端構建工具)來渲染應用程式整個使用者介面的用例。
React 如何使用 JavaScript?
React 利用現代 JavaScript 的特性來實現其許多模式。它與 JavaScript 最大的不同在於使用了 JSX 語法。JSX 擴充套件了 JavaScript 的語法,使得類似 HTML 的程式碼可以與其共存。例如:
const heading = <h1>Mozilla Developer Network</h1>;
這個標題常量被稱為 JSX 表示式。React 可以使用它在我們的應用程式中渲染 <h1> 標籤。
假設出於語義原因,我們想將標題包裝在 <header> 標籤中?JSX 方法允許我們像處理 HTML 一樣將元素相互巢狀:
const header = (
<header>
<h1>Mozilla Developer Network</h1>
</header>
);
注意: 上述程式碼片段中的括號並非 JSX 獨有,對你的應用程式沒有任何影響。它們只是向你(和你的計算機)表明括號內的多行程式碼屬於同一個表示式。你也可以這樣編寫 header 表示式:
const header = <header>
<h1>Mozilla Developer Network</h1>
</header>;
然而,這看起來有點笨拙,因為開始表示式的 <header> 標籤沒有與其相應的結束標籤對齊。
當然,你的瀏覽器無法在沒有幫助的情況下讀取 JSX。當編譯(使用 Babel 或 Parcel 等工具)後,我們的 header 表示式將如下所示:
const header = React.createElement(
"header",
null,
React.createElement("h1", null, "Mozilla Developer Network"),
);
可以跳過編譯步驟,使用 React.createElement() 來編寫你自己的 UI。但是,這樣做你會失去 JSX 的宣告式優勢,並且你的程式碼將變得更難閱讀。編譯是開發過程中的一個額外步驟,但 React 社群的許多開發人員認為 JSX 的可讀性是值得的。此外,現代前端開發幾乎總是涉及構建過程——你必須將現代語法降級以相容舊瀏覽器,並且你可能希望 壓縮 你的程式碼以最佳化載入效能。像 Babel 這樣的流行工具已經自帶 JSX 支援,因此除非你願意,否則你無需自己配置編譯。
由於 JSX 是 HTML 和 JavaScript 的混合體,一些開發者覺得它很直觀。另一些則說它的混合性質使其令人困惑。然而,一旦你習慣了它,它將讓你更快、更直觀地構建使用者介面,並讓其他人一眼就能更好地理解你的程式碼庫。
要了解更多關於 JSX 的資訊,請查閱 React 團隊的 使用 JSX 編寫標記 文章。
設定你的第一個 React 應用程式
有許多方法可以建立一個新的 React 應用程式。我們將使用 Vite 透過命令列建立一個新的應用程式。
可以透過將一些 <script> 元素複製到 HTML 檔案中來 將 React 新增到現有專案中,但使用 Vite 將讓你有更多時間構建應用程式,而花更少的時間在設定上。
注意: 你可以透過 Scrimba 的 第一個 React 程式碼 MDN 學習夥伴 scrim 來開始編寫 React 程式碼,而無需進行任何本地設定。在繼續之前,請隨意嘗試一下。
依賴項
為了使用 Vite,你需要安裝 Node.js。從 Vite 5.0 開始,至少需要 Node 18 或更高版本,並且在可能的情況下執行最新的長期支援 (LTS) 版本是個好主意。截至 2023 年 10 月 24 日,Node 20 是最新的 LTS 版本。Node 包括 npm(Node 包管理器)。
要檢查你的 Node 版本,請在終端中執行以下命令:
node -v
如果 Node 已安裝,你將看到版本號。如果沒有,你將看到錯誤訊息。要安裝 Node,請按照 Node.js 網站 上的說明進行操作。
你可以使用 Yarn 包管理器作為 npm 的替代品,但在這組教程中,我們將假設你使用 npm。有關 npm 和 yarn 的更多資訊,請參閱 包管理基礎。
如果你正在使用 Windows,你需要安裝一些軟體來與 Unix/macOS 終端保持一致,以便使用本教程中提到的終端命令。Git Bash(作為 Windows 版 git 工具集 的一部分)或 適用於 Linux 的 Windows 子系統 (WSL) 都適用。有關這些工具以及一般終端命令的更多資訊,請參閱 命令列速成課程。
另外請記住,在使用這些教程時,React 和 ReactDOM 生成的應用程式僅適用於 Firefox、Microsoft Edge、Safari 或 Chrome 等相當現代的瀏覽器。
請參閱以下內容獲取更多資訊:
初始化你的應用程式
npm 包管理器附帶了一個 `create` 命令,允許你從模板建立新專案。我們可以使用它從 Vite 的標準 React 模板建立一個新應用。確保你 `cd` 到你希望應用在你的機器上存在的目錄,然後在你的終端中執行以下命令:
npm create vite@latest moz-todo-react -- --template react
這會使用 Vite 的 `react` 模板建立一個 `moz-todo-react` 目錄。
注意: -- 對於向 `create` 等 npm 命令傳遞引數是必需的,並且 --template react 引數告訴 Vite 使用其 React 模板。
如果此命令成功,你的終端會列印一些訊息。你應該看到提示你 `cd` 到新目錄、安裝應用程式依賴項並在本地執行應用程式的文字。讓我們從其中兩個命令開始。在終端中執行以下命令:
cd moz-todo-react && npm install
過程完成後,我們需要啟動一個本地開發伺服器來執行我們的應用程式。在這裡,我們將向 Vite 的預設建議新增一些命令列標誌,以便伺服器啟動後立即在瀏覽器中開啟應用程式,並使用埠 3000。
在終端中執行以下命令:
npm run dev -- --open --port 3000
伺服器啟動後,你應該會看到一個新的瀏覽器選項卡,其中包含你的 React 應用程式。

應用程式結構
Vite 為我們提供了開發 React 應用程式所需的一切。其初始檔案結構如下:
moz-todo-react ├── README.md ├── index.html ├── node_modules ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.css │ ├── App.jsx │ ├── assets │ │ └── react.svg │ ├── index.css │ └── main.jsx └── vite.config.js
index.html 是最重要的頂層檔案。Vite 將你的程式碼注入到這個檔案中,以便你的瀏覽器可以執行它。在本教程中你不需要編輯這個檔案,但你應該更改此檔案中 <title> 元素內的文字,以反映你的應用程式的標題。準確的頁面標題對於可訪問性很重要。
public 目錄包含將直接提供給瀏覽器而無需經過 Vite 構建工具處理的靜態檔案。目前,它只包含一個 Vite 標誌。
src 目錄是我們大部分時間將花的地方,因為它是我們應用程式原始碼所在的地方。你會注意到此目錄中的某些 JavaScript 檔案以 .jsx 副檔名結尾。對於包含 JSX 的任何檔案,此副檔名是必需的——它告訴 Vite 將 JSX 語法轉換為瀏覽器可以理解的 JavaScript。src/assets 目錄包含你在瀏覽器中看到的 React 徽標。
`package.json` 和 `package-lock.json` 檔案包含我們專案的元資料。這些檔案並非 React 應用程式獨有:Vite 為我們填充了 `package.json`,而 npm 在我們安裝應用程式依賴項時建立了 `package-lock.json`。你無需完全理解這些檔案即可完成本教程。但是,如果你想了解更多資訊,可以在 npm 文件中閱讀有關 `package.json` 和 `package-lock.json` 的內容。我們還在 包管理基礎知識 教程中討論了 `package.json`。
自定義我們的開發指令碼
在我們繼續之前,你可能需要稍微修改你的 package.json 檔案,這樣你就不必每次執行 npm run dev 時都傳遞 --open 和 --port 標誌了。在你的文字編輯器中開啟 package.json 並找到 scripts 物件。將 "dev" 鍵更改為以下內容:
- "dev": "vite",
+ "dev": "vite --open --port 3000",
這樣設定後,每次執行 npm run dev,你的應用程式都會在瀏覽器中透過 https://:3000 開啟。
注意: 這裡你不需要額外的 --,因為我們是直接將引數傳遞給 vite,而不是傳遞給預定義的 npm 指令碼。
探索我們的第一個 React 元件 — <App />
在 React 中,元件是一個可重用的模組,它渲染我們整個應用程式的一部分。元件可以大也可以小,但它們通常定義清晰:它們服務於一個單一、明確的目的。
讓我們開啟 src/App.jsx,因為我們的瀏覽器正在提示我們編輯它。此檔案包含我們的第一個元件,<App />。
import { useState } from "react";
import viteLogo from "/vite.svg";
import reactLogo from "./assets/react.svg";
import "./App.css";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.com.tw" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.jsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
App.jsx 檔案由三個主要部分組成:頂部的 import 語句,中間的 App() 函式,以及底部的 export 語句。大多數 React 元件都遵循這種模式。
匯入語句
檔案頂部的 import 語句允許 App.jsx 使用在其他地方定義的程式碼。讓我們更仔細地看看這些語句。
import { useState } from "react";
import viteLogo from "/vite.svg";
import reactLogo from "./assets/react.svg";
import "./App.css";
第一條語句從 react 庫中匯入了 useState hook。Hook 是一種在元件內部使用 React 特性的方式。我們將在本教程後面詳細討論 hook。
之後,我們匯入 reactLogo 和 viteLogo。請注意,它們的匯入路徑分別以 ./ 和 / 開頭,並以 .svg 副檔名結尾。這告訴我們這些匯入是本地的,引用的是我們自己的檔案而不是 npm 包。
最後一條語句匯入了與我們的 <App /> 元件相關的 CSS。請注意,這裡沒有變數名,也沒有 from 指令。這被稱為 副作用匯入——它不會將任何值匯入到 JavaScript 檔案中,但它會告訴 Vite 將引用的 CSS 檔案新增到最終程式碼輸出中,以便在瀏覽器中使用。
App() 函式
在匯入之後,我們有一個名為 App() 的函式,它定義了 App 元件的結構。雖然大多數 JavaScript 社群喜歡像 helloWorld 這樣的 小駝峰命名,但 React 元件使用 Pascal Case(或大駝峰命名)變數名,例如 HelloWorld,以明確給定的 JSX 元素是 React 元件而不是常規 HTML 標籤。如果你將 App() 函式重新命名為 app(),你的瀏覽器將丟擲錯誤。
讓我們仔細看看 App()。
function App() {
const [count, setCount] = useState(0);
return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.com.tw" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.jsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
App() 函式返回一個 JSX 表示式。這個表示式定義了你的瀏覽器最終渲染到 DOM 的內容。
緊接著 return 關鍵字下方,有一個特殊的語法:<>。這是一個 片段。React 元件必須返回一個單獨的 JSX 元素,而片段允許我們這樣做,而無需在瀏覽器中渲染任意的 <div>。你會在許多 React 應用程式中看到片段。
export 語句
在 App() 函式之後還有一行程式碼:
export default App;
這個 export 語句使得我們的 App() 函式可以被其他模組使用。我們稍後會詳細討論這一點。
繼續 main
讓我們開啟 src/main.jsx,因為 <App /> 元件正在那裡使用。這個檔案是我們應用程式的入口點,它最初看起來像這樣:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.jsx";
createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>,
);
與 `App.jsx` 一樣,該檔案首先匯入它執行所需的所有 JavaScript 模組和其他資產。
前兩條語句從 react 和 react-dom 庫中匯入 StrictMode 和 createRoot,因為它們稍後在檔案中被引用。匯入這些庫時我們不寫入路徑或副檔名,因為它們不是本地檔案。事實上,它們在我們的 package.json 檔案中被列為依賴項。在學習本課時,請注意這種區別!
然後我們匯入我們的 App() 函式和 index.css,其中包含應用於整個應用程式的全域性樣式。
然後我們呼叫 createRoot() 函式,它定義了我們應用程式的根節點。它將我們希望 React 應用程式渲染的 DOM 元素作為引數。在這種情況下,它是 ID 為 root 的 DOM 元素。最後,我們將 render() 方法鏈式呼叫到 createRoot() 呼叫上,並將我們希望在根節點內渲染的 JSX 表示式傳遞給它。透過將 <App /> 作為此 JSX 表示式編寫,我們告訴 React 呼叫 App() 函式,該函式將 App 元件渲染到根節點內。
注意: <App /> 渲染在一個特殊的 <React.StrictMode> 元件內。此元件有助於開發人員捕獲其程式碼中的潛在問題。
如果你願意,可以查閱這些 React API:
重新開始
在開始構建我們的應用程式之前,我們將刪除 Vite 為我們提供的一些樣板程式碼。
首先,作為實驗,將 App.jsx 中的 <h1> 元素更改為“Hello, World!”,然後儲存檔案。你會注意到此更改會立即在瀏覽器中執行的開發伺服器 https://:3000 中渲染。在開發應用程式時請記住這一點。
我們不會使用其餘程式碼!將 App.jsx 的內容替換為以下內容:
import "./App.css";
function App() {
return (
<>
<header>
<h1>Hello, World!</h1>
</header>
</>
);
}
export default App;
JSX 實踐
接下來,我們將使用我們的 JavaScript 技能,更輕鬆地編寫 JSX 並使用 React 中的資料。我們將討論如何向 JSX 元素新增屬性、如何編寫註釋、如何從變數和其他表示式渲染內容,以及如何使用 props 將資料傳遞給元件。
向 JSX 元素新增屬性
JSX 元素可以擁有屬性,就像 HTML 元素一樣。嘗試在 App.jsx 檔案中 <h1> 元素下方新增一個 <button>,如下所示:
<button type="button">Click me!</button>
當你儲存檔案時,你會看到一個帶有“Click me!”字樣的按鈕。該按鈕目前沒有任何作用,但我們很快就會學習如何為我們的應用程式新增互動性。
某些屬性與它們的 HTML 對應物不同。例如,HTML 中的 `class` 屬性在 JSX 中轉換為 `className`。這是因為 `class` 是 JavaScript 中的保留字,而 JSX 是 JavaScript 的擴充套件。如果你想為按鈕新增一個 `primary` 類,你會這樣寫:
<button type="button" className="primary">
Click me!
</button>
作為內容的 JavaScript 表示式
與 HTML 不同,JSX 允許我們直接與內容一起編寫變數和其他 JavaScript 表示式。讓我們在 App.jsx 檔案中 App() 函式的上方宣告一個名為 subject 的變數:
const subject = "React";
function App() {
// code omitted for brevity
}
接下來,將 <h1> 元素中的單詞“World”替換為 {subject}:
<h1>Hello, {subject}!</h1>
儲存檔案並檢查你的瀏覽器。你應該看到“Hello, React!”被渲染。
subject 周圍的花括號是 JSX 語法的另一個特性。花括號告訴 React 我們要讀取 subject 變數的值,而不是渲染字面字串 "subject"。你可以在 JSX 的花括號內放置任何有效的 JavaScript 表示式;React 會對其進行求值並渲染表示式的結果作為最終內容。下面是一系列示例,上方有註釋解釋每個表示式將渲染什麼:
{/* Hello, React :)! */}
<h1>Hello, {`${subject} :)`}!</h1>
{/* Hello, REACT */}
<h1>Hello, {subject.toUpperCase()}</h1>
{/* Hello, 4! */}
<h1>Hello, {2 + 2}!</h1>
即使是 JSX 中的註釋也寫在花括號裡面!這是因為花括號可以包含一個 JavaScript 表示式,而註釋作為 JavaScript 表示式的一部分是有效的(並且會被忽略)。你可以在花括號內使用 /* 塊註釋語法 */ 和 // 行註釋語法(帶尾隨換行符)。
元件屬性(props)
Props 是將資料傳遞到 React 元件的一種方式。它們的語法與屬性(attribute)的語法相同,事實上:prop="value"。不同之處在於,屬性是傳遞給普通元素的,而 props 是傳遞給 React 元件的。
在 React 中,資料流是單向的:props 只能從父元件向下傳遞到子元件。
讓我們開啟 main.jsx 併為我們的 <App /> 元件新增它的第一個 prop。
向 <App /> 元件呼叫新增一個 subject 屬性,其值為 Clarice。完成後,它應該看起來像這樣:
<App subject="Clarice" />
回到 App.jsx,讓我們重新審視 App() 函式。更改 App() 的簽名,使其接受 props 作為引數,並將 props 記錄到控制檯以便你可以檢查它。還要刪除 subject 常量;我們不再需要它了。你的 App.jsx 檔案應該如下所示:
function App(props) {
console.log(props);
return (
<>
{
// code omitted for brevity
}
</>
);
}
儲存檔案並檢查你的瀏覽器。你會看到一個空白背景,沒有任何內容。這是因為我們正在嘗試讀取一個不再定義的 subject 變數。透過註釋掉 <h1>Hello {subject}!</h1> 行來修復此問題。
注意: 如果你的程式碼編輯器能夠解析 JSX(大多數現代編輯器都可以!),你可以使用其內建的註釋快捷鍵——Ctrl + /(Windows 上)或 Cmd + /(macOS 上)——來更快地建立註釋。
儲存檔案並註釋掉那一行。這次,你應該會看到“Click me!”按鈕獨自渲染。如果你開啟瀏覽器的開發人員控制檯,你將看到如下訊息:
Object { subject: "Clarice" }
物件屬性 subject 對應於我們新增到 <App /> 元件呼叫中的 subject prop,字串 Clarice 對應於其值。React 中的元件 props 總是以這種方式收集到物件中。
讓我們使用這個 subject prop 來修復我們應用程式中的錯誤。取消註釋 <h1>Hello, {subject}!</h1> 行並將其更改為 <h1>Hello, {props.subject}!</h1>,然後刪除 console.log() 語句。你的程式碼應該如下所示:
function App(props) {
return (
<>
<header>
<h1>Hello, {props.subject}!</h1>
<button type="button" className="primary">
Click me!
</button>
</header>
</>
);
}
儲存後,應用程式現在應該會顯示“Hello, Clarice!”。如果你返回到 main.jsx,編輯 subject 的值,然後儲存,你的文字將會改變。
為了進一步練習,你可以嘗試在 main.jsx 中的 <App /> 元件呼叫中新增一個額外的 greeting prop,並在 App.jsx 中與 subject prop 一起使用它。
總結
至此,我們對 React 的初步瞭解就結束了,包括如何在本地安裝它、建立入門應用程式以及基本原理。在下一篇文章中,我們將開始構建我們的第一個真正的應用程式——一個待辦事項列表。不過在此之前,讓我們回顧一下我們學到的一些知識。
在 React 中
- 元件可以匯入所需的模組,並且必須在檔案底部匯出自身。
- 元件函式使用
PascalCase命名。 - 你可以透過將 JavaScript 表示式放在花括號之間,例如
{so},來在 JSX 中渲染它們。 - 某些 JSX 屬性與 HTML 屬性不同,以免與 JavaScript 保留字衝突。例如,HTML 中的
class在 JSX 中轉換為className。 - Props 的寫法與元件呼叫中的屬性完全相同,並傳遞給元件。