剛開始接觸 props
時難免有點霧裡看花的感覺,但其實 props
的概念和 JavaScript 函式的參數非常類似。用這篇文章來記錄一下 props
的基本使用方式和注意事項。
props
?如何傳遞資料?props
其實為 properties 的縮寫,而在 JavaScript 的世界中,看到 property,我們直覺會聯想到物件屬性,而 props
的確和物件有關係。
props
是 React 提供的特殊物件,讓我們將父元件的資料傳遞給子元件。
沒錯,日後只要看到 props
,就想像它承載了喬斯達家族的精神,不斷傳遞給下一代的 JOJO 就對了。這樣的運作方式我們其實不陌生,先來回想一下 JavaScript 函式參數吧
function sum() {
return a + b;
}
sum(); // Reference Error: a is not defined
sum()
函式取用了 a、b 兩個值,但不知道它們是何許人也,所以跳出 Reference Error。解決的方法很簡單,將 a、b 當作參數帶入函式即可。
function sum(a, b) {
return a + b;
}
sum(2, 2); // 4
正在學習 React 的我們都知道,元件 (component) 其實就是 JavaScript 函式,所以我們理當能用參數的方式來傳遞資料。但再進一步回想,元件一定要回傳 (return) 一組 JSX 讓 React 進行渲染,而 JSX 和 HTML 標記又非常類似,因此我們不妨將想要傳遞下去的黃金精神資料,以 attribute 的方式寫進 JSX 裡面。
看到了嗎?name
和 color
就是 props
!
function App() {
return <Spirit name="黃金精神" color="golden" />;
}
function Spirit() {
return <div>目前還沒有取用傳遞下來的資料喔</div>;
}
props
能傳遞的資料類型不限字串,數值、陣列、物件、函式都可以。實務上還滿常傳遞物件的,請參考以下程式碼:
const spiritObj = {
name: "黃金精神",
color: "golden",
value : [
"integrity",
"pride",
"brave",
"dedication"
]
};
function App() {
return <Spirit spiritObj={spiritObj} />;
}
function Spirit() {
return <div>目前還沒有取用傳遞下來的資料喔</div>;
}
透過 props
,App
就可以將資料傳遞給子元件 Spirit
囉。學會傳遞資料之後,接下來還得取用傳下來的資料。
props
資料前面提過 props
本身是 React 提供的物件,因此我們傳遞的資料,其實都包含在 props
物件裡面了。想一探究竟的話,可以把 props
先列印在 console 喬喬瞧瞧。
export default function App() {
return <Spirit spiritObj={spiritObj} />;
}
function Spirit(props) { // Add props as parameter
console.log(props); // Print props object
return <div>目前還沒有取用傳遞下來的資料喔</div>;
}
太好了,那我們使用 dot notation 不就可以取用資料了嗎?的確是這樣沒錯:
const spiritObj = {
name: "黃金精神",
color: "golden",
value: ["integrity", "pride", "brave", "dedication"],
};
export default function App() {
return <Spirit spiritObj={spiritObj} />;
}
function Spirit(props) {
return (
<div style={{ backgroundColor: props.spiritObj.color }}>
{props.spiritObj.name}
</div>
);
}
但由於現在包了兩層物件,所以資料取用的寫法難免冗長,這時候善用解構賦值會是不錯的選項。直接在子元件的 (...)
當中解構,明確指名要使用的 props
資料:
// Before using destructuring
function Spirit(props) {
return (
<div style={{ backgroundColor: props.spiritObj.color }}>
{props.spiritObj.name}
</div>
);
}
// After using destructuring
function Spirit({ spiritObj }) {
return (
<div style={{ backgroundColor: spiritObj.color }}>
{spiritObj.name}
</div>
);
}
截至目前來做個小整理:
props
是 React 提供的特殊物件,裡面承載父元件要傳遞給子元件的資料,有助於我們去架構、客製化元件,就像 JavaScript 函示的參數。props
傳遞,舉凡字串、數值、陣列、物件,甚至元件。props.<key>
的寫法取值,可以善用解構寫法,直接定義 props 當中要使用的資料。props
注意事項props
是 read-only 的,也就是只能被拿來讀取,無法被更改。聽起來好麻煩喔,為什麼要設下這種規定?因為 React 講求 pure function,其中一項規則,就是函式不能更改 function scope 外面的值。套用到 props 的使用情境,字元件函式不能去改變父元件傳遞下來的資料,要記得資料還是屬於父元件的。
打破 pure function 原則的話,容易形成副作用 (side-effect),造成 debug 的問題,終究也是害到我們這些始作俑者。
如果真要更改props
,請改用state
React 採取單向資料流模式,意即資料傳遞僅能由父元件往下傳給子元件,子元件無法逆流將資料往上傳給父元件。這種模式的好處如下:
題外話,Angular 似乎是採用雙向資料流,但沒有那方面的實作經驗,日後遇到會再補充上來。
總而言之,單向資料流讓 props
僅能由上往下傳遞,但 React 似乎有種叫做 controled component 的東西可以達到雙向的效果,這部分也留待日後研究:Understanding data binding in React