前言
沿用上篇的例子,假設我們現在要將 menu list 單獨拉出來變成一個能被重複使用的元件(好讓每個頁面都能看見美味菜單),首先要做的當然是建立一個 MenuList.js 的元件檔:
接著,在要引入該元件的頁面中 import 並引入…
登愣,報錯了。
這是理所當然的,因為每個元件中的 data 都獨立存在。換句話說,在 MenuList 這個元件中無法取得 Home 元件的 data 。
雖然我們當然也可以原封不動把 Home 裡的資料搬到 MenuList 中,但如果今天有另一個頁面元件也要引入 MenuList ,而他需要的資料陣列,偏偏和 Home 需要的不一樣,那該怎麼辦呢?又或者是, Home 這個頁面引入五個元件,而這些元件需要的資料其實都大同小異,如果在元件各自取資料,好像又太過累贅,要如何改寫程式碼呢?
Props
講了這麼久終於要讓主角登場。 Props 可以讓資料從父元件單向傳遞到子元件當中,單向傳遞的意思就是不能改變的意思。在上面的例子裡, Home.js 是父元件, MenuList 則是子元件。透過 Props ,我們終於能把資料放在 Home.js ,並讓 MenuList 來引用他的資料。
改寫一下 Home.js :
<MenuList> 裡前面的 menu 代表子元件取用資料使用的名稱,後面的代表要傳遞的資料。除了傳遞陣列,也可以傳入普通的字串。
接著改寫 MenuList.js :
傳入的資料會放入函式參數中,可以命名為 Props 。 Props 傳遞的資料會被放在一個物件當中,裡頭則用剛剛在父元件命名的名稱作為屬性名。舉例來說,要取用剛才的 menu 陣列資料要打:
const menu = props.menu;
不過這種寫法還是有點太囉唆。讓我們在本來寫 Props 的位置,改成直接放入這個元件要使用的 Props 物件屬性名稱。
上述寫法和 Props example-2 (MenuList.js) 能達成完全相同的結果。
重複使用元件
如同前面所說, Props 可以幫助我們達成重用元件的目標。簡單舉個例子, Home 頁有兩個區塊,一個區塊要顯示所有的菜單,另一個只顯示有用到蛋的菜單。
可以知道其實我們只需要一個 menu 陣列,列出全部資料,再做篩選就好。請看看下面實際撰寫的範例:
聰明的你一定已經發現了,透過 Props ,只用一個 Home.js 和一個 MenuList.js 就能夠生成好幾個不同內容物的區塊。假設今天資料不是寫死在程式碼,而是去跟資料庫要,只取一次資料可以大幅縮短跑頁面的時間。當然,也會更容易維護。
Props 與函式
雖然 Props 不可改變,但可以把父元件的 set 函式當成 Props 傳給子元件,在子元件呼叫父元件的 State 更改後重渲染,只要父元件的 State 有更新, State 值就會再變成新的 Props 傳給子元件。
除此之外,要將子元件的資料傳給父元件,也可以透過 Props 搭配函式。舉例來說,假設這是一個產品管理後台,而我要在每個產品後面加上刪除按鈕。刪除按鈕本身被放在子元件,但處理刪除的函式 handleDelete 被放在父元件。為了讓 handleDelete 能判斷哪一項要被刪除,必須從子元件傳要刪除的 id 到父元件。我們可以用下面的方式來撰寫。
嘿,別忘了!對 React 來說,要更動資料必須要透過 setState() 。並且,要使用函式傳遞參數,外頭要包上一個大括號。
你可能會覺得奇怪,幹嘛不把 handleDelete() 放在子元件就好,省得麻煩。這是因為 setMenu() 是在父元件被定義的,資料也在父元件初始化,最重要的是我們也不該去直接從子元件更動傳進來的 Props 值!所以最好還是回到父元件做處理。
比較 State 與 Props
最後來比較一下 State 和 Props 的差異。
- State 是讓元件控制自己本身,可以被改變
- Props 是讓外面的父元件對自己進行配置,唯讀不能改變
系列連結
Medium 不太好找前後篇文章,所以在這個系列文章最後,放入任意門連結,希望能幫助到你!