傳遞 Props 到 Component 中
React components 使用 props 相互通信。每個父組件可以通過給子組件傳遞 props 來傳遞一些信息。 Props 可能讓你想起 HTML attributes,但你可以通過它們傳遞任何 JavaScript 值,包括對象、數組和函數。
You will learn
- 如何向 component 傳遞 props
- 如何從 component 中讀取props
- 如何為 props 指定默認值
- 如何向 component 傳遞一些JSX
- props 如何隨著時間變化
熟悉 props
Props 是你傳遞給 JSX 標籤的信息。例如,className
、src
、alt
、width
和 height
是你可以傳遞給 <img>
標籤的一些 props:
function Avatar() { return ( <img className="avatar" src="https://i.imgur.com/1bX5QH6.jpg" alt="Lin Lanying" width={100} height={100} /> ); } export default function Profile() { return ( <Avatar /> ); }
可以傳遞給 <img>
標籤的 props 已被預定義了(ReactDOM 符合 the HTML standard 標準)。但是,你可以向自己的組件(例如 <Avatar>
)傳遞任何 props 以自定義它們。以下是如何操作:
向 Component 傳遞 props
在這段代碼中,Profile
component 沒有向它的 child component, Avatar
傳遞任何 props:
export default function Profile() {
return (
<Avatar />
);
}
你可以通過兩個步驟為 Avatar
提供一些 props。
第一步:向 child component 傳遞 props
首先,向 Avatar
傳遞一些 props。例如,讓我們傳遞兩個 props:person
(一個對象)和 size
(一個數字):
export default function Profile() {
return (
<Avatar
person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
size={100}
/>
);
}
如果
person=
後面的雙花括號讓你感到困惑,請記住,它們只是 JSX 花括號中的一個對象。
現在,你可以在 Avatar
component 內部讀取這些 props。
第二步:在 child component 中讀取 props
你可以通過在 function Avatar
之後的 ({
和 })
內部用逗號分隔它們的名稱 person,size
來讀取這些 props。這使你可以在 Avatar
代碼中使用它們,就像使用變量一樣。
function Avatar({ person, size }) {
// person and size are available here
}
為 Avatar
添加一些使用 person
和 size
props 進行渲染的邏輯,然後就完成了。
現在,你可以使用不同的 props 配置 Avatar
以多種不同的方式進行呈現。試著調整這些值!
import { getImageUrl } from './utils.js'; function Avatar({ person, size }) { return ( <img className="avatar" src={getImageUrl(person)} alt={person.name} width={size} height={size} /> ); } export default function Profile() { return ( <div> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> <Avatar size={80} person={{ name: 'Aklilu Lemma', imageId: 'OKS67lh' }} /> <Avatar size={50} person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} /> </div> ); }
Props 讓你獨立思考 parent 和 child components。例如,你可以在 Profile
內部更改 person
或 size
,而無需考慮 Avatar
如何使用它們。同樣的,你可以更改 Avatar
如何使用這些 props,不必考慮到 Profile
。
你可以將 props 視為可以調節的“旋鈕”。它們扮演著函數所需的參數的相同角色——實際上,props 就是 你組件的唯一參數! React component 函數接受一個單獨的參數,一個名為 props 的對象:
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}
通常你不需要整個 props
對象本身,所以你可以使用解構將其拆分成單個 props 變量。
為 prop 指定默認值
如果你想給一個 prop 一個默認值以在沒有指定值時使用,你可以通過在參數後面放置 =
和默認值來實現解構:
function Avatar({ person, size = 100 }) {
// ...
}
現在,如果在沒有 size
prop 的情況下渲染 <Avatar person={...} />
,則 size
將被設置為 100
。
默認值僅在缺少 size
prop 或傳遞 size={undefined}
時使用。 但是,如果你傳遞 size={null}
或 size={0}
,默認值將不被使用。
使用 JSX 展開语法轉發 props
有時,傳遞 props 會變得非常重複:
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
重複代碼沒有錯——它可以更易讀。 但有時你可能會看重簡潔。 一些 components 將它們的所有 props 轉發給它們的子組件,就像這個 Profile
如何處理 Avatar
一樣。 因為他們不直接使用他們的任何 props,所以使用更簡潔的”展開“語法是有意義的:
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
這將會轉發所有 Profile
的 props 給 Avatar
而無需列出每個 props 的名字。
有節制地使用擴展語法。 如果你在所有其他 component 中都使用它,那就有問題了。 通常,它表示你應該拆分 components 並將子組件作為 JSX 傳遞。 接下來會詳細介紹!
傳遞 JSX 为 children
嵌套瀏覽器標籤是很常見的:
<div>
<img />
</div>
有時你會希望以相同的方式嵌套自己的組件:
<Card>
<Avatar />
</Card>
當你將內容嵌套在 JSX 標籤中時,parent component 將在名為 children 的 prop 中接收該內容。 例如,下面的 Card
組件將接收一個為 <Avatar/>
的 children
屬性並將其渲染在被嵌套的 div 中:
import Avatar from './Avatar.js'; function Card({ children }) { return ( <div className="card"> {children} </div> ); } export default function Profile() { return ( <Card> <Avatar size={100} person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2' }} /> </Card> ); }
嘗試使用一些文本替換 <Card>
中的 <Avatar>
以查看 Card
組件如何包裝任何嵌套內容。 它不需要“知道”其內部渲染的是什麼。 你會在很多地方看到這種靈活的模式。
你可以將擁有 children
prop 的 component 看作是具有可以由其 parent component 用任意 JSX “填充”的“孔”。你通常會使用 children prop 來創建可視化包裝器,例如面板,網格等。
Illustrated by Rachel Lee Nabors
props 如何隨時間變化
下面的 Clock
component 從其 parent component 接收兩個 prop:顏色
和 時間
。 (省略了 parent component 的代碼,因為它使用了我們暫時不會深入探討的 state。)
嘗試在下面的選擇框中更改顏色:
export default function Clock({ color, time }) { return ( <h1 style={{ color: color }}> {time} </h1> ); }
這個例子說明了一個 component 可能會隨著時間的推移接收到不同的 props。 Props 並不總是靜態的! 在這裡,time
prop 每秒都在變化,而 color
prop 會在你選擇另一種顏色時發生變化。 Props 反映 component 在任何時間點的數據,而不僅僅是在開始時。
然而,props 是 immutable——計算機科學中的一個術語,意思是“不可改變的”。 當 component 需要更改其 props 時(例如,響應用戶交互或新數據),它將不得不“請求”其 parent component 向它傳遞 不同的 props —— 一個新的對象! 舊的 props 將被丟棄,最終 JavaScript 引擎將回收它們佔用的內存。
不要試圖“改變 props”。 當你需要響應用戶輸入(比如改變選擇的顏色)時,你將需要“設置狀態”,你可以在 State: Component 的記憶。 學習。
Recap
- 要傳遞 props,將它們添加到 JSX,就像使用 HTML attributes 一樣。
- 要讀取 props,請使用
function Avatar({ person, size })
解構語法。 - 你可以指定一個默認值,例如
size = 100
,用於缺失和undefined
的props。 - 你可以使用
<Avatar {...props} />
JSX 展開語法轉發所有 props,但不要過度使用它! - 像
<Card><Avatar /></Card>
這樣的嵌套 JSX 將顯示為Card
component 的children
props。 - Props 是時間上的只讀快照:每次渲染都會收到一個新版本的 props。
- 你不能改變 props。 當你需要交互時,你需要設置 state。
Challenge 1 of 3: 提取 component
這個 Gallery
component 包含兩個非常相似的 profile 標籤。 從中提取一個 Profile
組件以減少重複。 你需要選擇什麼 props 應該被傳遞。
import { getImageUrl } from './utils.js'; export default function Gallery() { return ( <div> <h1>Notable Scientists</h1> <section className="profile"> <h2>Maria Skłodowska-Curie</h2> <img className="avatar" src={getImageUrl('szV5sdG')} alt="Maria Skłodowska-Curie" width={70} height={70} /> <ul> <li> <b>Profession: </b> physicist and chemist </li> <li> <b>Awards: 4 </b> (Nobel Prize in Physics, Nobel Prize in Chemistry, Davy Medal, Matteucci Medal) </li> <li> <b>Discovered: </b> polonium (element) </li> </ul> </section> <section className="profile"> <h2>Katsuko Saruhashi</h2> <img className="avatar" src={getImageUrl('YfeOqp2')} alt="Katsuko Saruhashi" width={70} height={70} /> <ul> <li> <b>Profession: </b> geochemist </li> <li> <b>Awards: 2 </b> (Miyake Prize for geochemistry, Tanaka Prize) </li> <li> <b>Discovered: </b> a method for measuring carbon dioxide in seawater </li> </ul> </section> </div> ); }