學(xué)習(xí)(React 官方中文文檔)[https://zh-hans.react.dev/]
快速入門
創(chuàng)建和嵌套組件
React 應(yīng)用程序是由 組件 組成的。一個(gè)組件是 UI(用戶界面)的一部分,它擁有自己的邏輯和外觀。組件可以小到一個(gè)按鈕,也可以大到整個(gè)頁(yè)面。
React 組件是返回標(biāo)簽的 JavaScript 函數(shù):
function MyButton() {
return (
<button>我是一個(gè)按鈕</button>
)
}
至此,你已經(jīng)聲明了 MyButton,現(xiàn)在把它嵌套到另一個(gè)組件中:
export default function App() {
return (
<div>
<h1>歡迎來(lái)到我的應(yīng)用</h1>
<MyButton />
</div>
);
}
你可能已經(jīng)注意到 <MyButton /> 是以大寫字母開(kāi)頭的。你可以據(jù)此識(shí)別 React 組件。React 組件必須以大寫字母開(kāi)頭,而 HTML 標(biāo)簽則必須是小寫字母。
效果:

export default 關(guān)鍵字指定了文件中的主要組件
使用JSX編寫標(biāo)簽
上面所使用的標(biāo)簽語(yǔ)法被稱為 JSX。它是可選的,但大多數(shù) React 項(xiàng)目會(huì)使用 JSX,主要是它很方便。
JSX 比 HTML 更加嚴(yán)格。你必須閉合標(biāo)簽,如 <br />。你的組件也不能返回多個(gè) JSX 標(biāo)簽。你必須將它們包裹到一個(gè)共享的父級(jí)中,比如 <div>...</div> 或使用空的 <>...</> 包裹:
function AboutPage() {
return (
<>
<h1>關(guān)于</h1>
<p>你好。<br />最近怎么樣?</p>
</>
)
}
如果你有大量的 HTML 需要移植到 JSX 中,你可以使用 在線轉(zhuǎn)換器。
添加樣式
在 React 中,你可以使用 className 來(lái)指定一個(gè) CSS 的 class。它與 HTML 的 class 屬性的工作方式相同:
<img className="avatar" />
然后,你可以在一個(gè)單獨(dú)的 CSS 文件中為它編寫 CSS 規(guī)則:
/* 在你的 CSS 文件中修改 */
.avatar {
border-radius: 50%;
}
React 并沒(méi)有規(guī)定你如何添加 CSS 文件。最簡(jiǎn)單的方式是使用 HTML 的 <link> 標(biāo)簽
顯示數(shù)據(jù)
JSX 會(huì)讓你把標(biāo)簽放到 JavaScript 中。而大括號(hào)會(huì)讓你 “回到” JavaScript 中,這樣你就可以從你的代碼中嵌入一些變量并展示給用戶。例如,這將顯示 user.name:
return (
<h1>
{user.name}
</h1>
);
你還可以將 JSX 屬性 “轉(zhuǎn)義到 JavaScript”,但你必須使用大括號(hào) 而非 引號(hào)。例如,className="avatar" 是將 "avatar" 字符串傳遞給 className,作為 CSS 的 class。但 src={user.imageUrl} 會(huì)讀取 JavaScript 的 user.imageUrl 變量,然后將該值作為 src 屬性傳遞:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
你也可以把更為復(fù)雜的表達(dá)式放入 JSX 的大括號(hào)內(nèi),例如 字符串拼接:
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90,
};
export default function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
);
}

在上面示例中,style={{}} 并不是一個(gè)特殊的語(yǔ)法,而是 style={ } JSX 大括號(hào)內(nèi)的一個(gè)普通 {} 對(duì)象。當(dāng)你的樣式依賴于 JavaScript 變量時(shí),你可以使用 style 屬性。
條件渲染
React 沒(méi)有特殊的語(yǔ)法來(lái)編寫條件語(yǔ)句,因此你使用的就是普通的 JavaScript 代碼。例如使用 if 語(yǔ)句根據(jù)條件引入 JSX:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
如果你喜歡更為緊湊的代碼,可以使用 條件 ? 運(yùn)算符。與 if 不同的是,它工作于 JSX 內(nèi)部:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
當(dāng)你不需要 else 分支時(shí),你也可以使用更簡(jiǎn)短的 邏輯 && 語(yǔ)法:
<div>
{isLoggedIn && <AdminPanel />}
</div>
所有這些方法也適用于有條件地指定屬性。如果你對(duì) JavaScript 語(yǔ)法不熟悉,你可以先使用 if...else。
渲染列表
你將依賴 JavaScript 的特性,例如 for 循環(huán) 和 array 的 map() 函數(shù) 來(lái)渲染組件列表。
假設(shè)你有一個(gè)產(chǎn)品數(shù)組:
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
在你的組件中,使用 map() 函數(shù)將這個(gè)數(shù)組轉(zhuǎn)換為 <li> 標(biāo)簽構(gòu)成的列表:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
注意, <li> 有一個(gè) key 屬性。對(duì)于列表中的每一個(gè)元素,你都應(yīng)該傳遞一個(gè)字符串或者數(shù)字給 key,用于在其兄弟節(jié)點(diǎn)中唯一標(biāo)識(shí)該元素。通常 key 來(lái)自你的數(shù)據(jù),比如數(shù)據(jù)庫(kù)中的 ID。如果你在后續(xù)插入、刪除或重新排序這些項(xiàng)目,React 將依靠你提供的 key 來(lái)思考發(fā)生了什么。
const products = [
{ title: '卷心菜', isFruit: false, id: 1 },
{ title: '大蒜', isFruit: false, id: 2 },
{ title: '蘋果', isFruit: true, id: 3 },
];
export default function ShoppingList() {
const listItems = products.map(product =>
<li
key={product.id}
style={{
color: product.isFruit ? 'magenta' : 'darkgreen'
}}
>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
}

響應(yīng)事件
你可以通過(guò)在組件中聲明 事件處理 函數(shù)來(lái)響應(yīng)事件:
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
點(diǎn)我
</button>
);
}
注意,onClick={handleClick} 的結(jié)尾沒(méi)有小括號(hào)!不要 調(diào)用 事件處理函數(shù):你只需 把函數(shù)傳遞給事件 即可。當(dāng)用戶點(diǎn)擊按鈕時(shí) React 會(huì)調(diào)用你傳遞的事件處理函數(shù)。
更新界面
通常你會(huì)希望你的組件 “記住” 一些信息并展示出來(lái),比如一個(gè)按鈕被點(diǎn)擊的次數(shù)。要做到這一點(diǎn),你需要在你的組件中添加 state。
首先,從 React 引入 useState:
import { useState } from 'react';
現(xiàn)在你可以在你的組件中聲明一個(gè) state 變量:
function MyButton() {
const [count, setCount] = useState(0);
// ...
你將從 useState 中獲得兩樣?xùn)|西:當(dāng)前的 state(count),以及用于更新它的函數(shù)(setCount)。你可以給它們起任何名字,但按照慣例會(huì)像 [something, setSomething] 這樣為它們命名。
第一次顯示按鈕時(shí),count 的值為 0,因?yàn)槟惆?0 傳給了 useState()。當(dāng)你想改變 state 時(shí),調(diào)用 setCount() 并將新的值傳遞給它。點(diǎn)擊該按鈕計(jì)數(shù)器將遞增:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
React 將再次調(diào)用你的組件函數(shù)。第一次 count 變成 1。接著點(diǎn)擊會(huì)變成 2。繼續(xù)點(diǎn)擊會(huì)逐步遞增。
如果你多次渲染同一個(gè)組件,每個(gè)組件都會(huì)擁有自己的 state。你可以嘗試點(diǎn)擊不同的按鈕:
import { useState } from 'react';
export default function MyApp() {
return (
<div>
<h1>獨(dú)立更新的計(jì)數(shù)器</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
點(diǎn)了 {count} 次
</button>
);
}

注意,每個(gè)按鈕會(huì) “記住” 自己的 count,而不影響其他按鈕。
使用Hook
以 use 開(kāi)頭的函數(shù)被稱為 Hook。useState 是 React 提供的一個(gè)內(nèi)置 Hook。你可以在 React API 參考 中找到其他內(nèi)置的 Hook。你也可以通過(guò)組合現(xiàn)有的 Hook 來(lái)編寫屬于你自己的 Hook。
Hook 比普通函數(shù)更為嚴(yán)格。你只能在你的組件(或其他 Hook)的 頂層 調(diào)用 Hook。如果你想在一個(gè)條件或循環(huán)中使用 useState,請(qǐng)?zhí)崛∫粋€(gè)新的組件并在組件內(nèi)部使用它。
組件間共享數(shù)據(jù)
在前面的示例中,每個(gè) MyButton 都有自己獨(dú)立的 count,當(dāng)每個(gè)按鈕被點(diǎn)擊時(shí),只有被點(diǎn)擊按鈕的 count 才會(huì)發(fā)生改變:

然而,你經(jīng)常需要組件 共享數(shù)據(jù)并一起更新。
為了使得 MyButton 組件顯示相同的 count 并一起更新,你需要將各個(gè)按鈕的 state “向上” 移動(dòng)到最接近包含所有按鈕的組件之中。

此刻,當(dāng)你點(diǎn)擊任何一個(gè)按鈕時(shí),MyApp 中的 count 都將改變,同時(shí)會(huì)改變 MyButton 中的兩個(gè) count
具體代碼如下:
首先,將 MyButton 的 state 上移到 MyApp 中:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>獨(dú)立更新的計(jì)數(shù)器</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... 我們正在從這里移動(dòng)代碼...
}
接著,將 MyApp 中的點(diǎn)擊事件處理函數(shù)以及 state 一同向下傳遞到 每個(gè) MyButton 中。你可以使用 JSX 的大括號(hào)向 MyButton 傳遞信息。就像之前向 <img> 等內(nèi)置標(biāo)簽所做的那樣:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>共同更新的計(jì)數(shù)器</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
使用這種方式傳遞的信息被稱作 prop。此時(shí) MyApp 組件包含了 count state 以及 handleClick 事件處理函數(shù),并將它們作為 prop 傳遞給 了每個(gè)按鈕。
最后,改變 MyButton 以 讀取 從父組件傳遞來(lái)的 prop:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
點(diǎn)了 {count} 次
</button>
);
}
當(dāng)你點(diǎn)擊按鈕時(shí),onClick 處理程序會(huì)啟動(dòng)。每個(gè)按鈕的 onClick prop 會(huì)被設(shè)置為 MyApp 內(nèi)的 handleClick 函數(shù),所以函數(shù)內(nèi)的代碼會(huì)被執(zhí)行。該代碼會(huì)調(diào)用 setCount(count + 1),使得 state 變量 count 遞增。新的 count 值會(huì)被作為 prop 傳遞給每個(gè)按鈕,因此它們每次展示的都是最新的值。這被稱為“狀態(tài)提升”。通過(guò)向上移動(dòng) state,我們實(shí)現(xiàn)了在組件間共享它。
import { useState } from 'react';
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>共同更新的計(jì)數(shù)器</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
點(diǎn)了 {count} 次
</button>
);
}