3-6 React 元件間的資料傳遞 - props 的使用
本單元對應的專案分支為:pass-props-to-components。
在上一個單元中已經拆分出了兩個獨立的 React 元件 - UnitControl 和 CardFooter。現在我們想要讓 CardFooter 能夠根據使用者輸入的網速快慢來顯示不同的文字內容和顏色樣式。
在上一章中,我們已經學過如何讓 JSX 能夠根據不同的資料狀態來呈現不同的內容,所以條件轉譯和動態切換 CSS 樣式的方式其實你應該已經知道了。比較不一樣的地方是,現在使用者輸入的網速 inputValue 這個狀態是保存在 App 這個元件中,而 CardFooter 是一個獨立的元件,CardFooter 並沒有辦法直接知道 App 中 inputValue 的值是多少,必須要把這個值從 App 傳遞到 CardFooter 後,CardFooter 才會知道 inputValue 的值。因此這裡我們就需要先來了解如何在 React 各元件之間進行的資料傳遞。
透過 props 在元件間傳遞資料狀態#
先讓我們用一張圖來描述當前網速單位換算器的結構:

從上圖中可以看到,在專案中現在一共有三個 React 元件,其中最上層的 App 裡面會包含 inputValue 這個狀態(state)和用來改變這個狀態的 setInputValue 這個方法。
接著在 App 這個元件中還匯入並使用了 UnitControl 和 CardFooter 這兩個元件,在這樣的關係中,我們會說 App 是父層元件(parent component),UnitControl 和 CardFooter 是子層元件(child component)。
小提醒
父層和子層是相對的概念,例如這裡 UnitControl 是 App 的子層元件,但若在 UnitControl 中還有匯入並使用另一個元件,這時候 UnitControl 則會是另一個元件的父層元件。
從這張圖中我們可以看到,因為 inputValue 的狀態是保存在 App 中,因此 CardFooter 並沒有辦法直接知道 inputValue 的值。在 React 中,子層元件如果想要得到父層元件的資料狀態,只需要透過 props 的方式來傳送資料就可以了:

講解完了概念之後,讓我們來看具體要怎麼做。
父層透過 props 傳遞資料#
父層要傳遞 props 到子層的方式非常簡單,假設現在我們有名為 ChildComponent 的子層元件,想要把父層元件中的 firstName 和 lastName 這兩個資料傳遞進 ChildComponent 中,只需要透過像是 HTML 屬性的方式傳進去就可以了:
子層元件接收 props 資料的方式#
接著子層元件 ChildComponent 只需要透過「函式參數」的方式來接收父層元件傳進來的 firstName 和 lastName 即可。這裡我們透過在函式參數中帶入 props 這個參數,即可取得父層傳進來的資料,透過 props.firstName 和 props.lastName 就可取得對應的值:
小提醒
這裡慣例上會把函式參數的名稱稱作 props 但實際上名稱是可以自由命名的。
在取用 props 的時候,會習慣使用解構賦值直接把需要的變數取出來,因此在取用 props 的地方會像這樣寫:
甚至更精簡到連 props 都不命名了,直接在參數中透過解構賦值取出來用:
上面這些都是很常見的寫法。
將 inputValue 傳遞到 CardFooter 中使用#
回到網速單位換算器,現在想要把父層元件 App 的資料 inputValue 透過 props 傳到子層的 CardFooter 元件中,只需要透過像是 HTML 屬性的方式傳進去就可以了。
透過 props 將 inputValue 從 App 傳入 CardFooter#
我們可以在 <App /> 元件中使用 <CardFooter /> 的地方,把想要傳入的資料透過 <CardFooter key={value} /> 的方式傳入,在 value 的地方把想要傳遞到 CardFooter 的資料值帶入,也就是 inputValue;在 key 的地方,方便起見我們一樣取名為 inputValue,但這並不是一定的,名稱同樣可以自行命名,而這個 key 會用在 CardFooter 接收 props 時使用:
小提醒
key 的命名主要是讓子層元件取用 props 時使用,並沒有硬性規定要用什麼名稱,只是這裡剛好都取做 inputValue。
在 CardFooter 從 props 取得 App 傳進來的 InputValue#
接著在 <CardFooter /> 的元件中,就可以在參數中透過 props 取得傳進來的資料,props 本身會是一個物件,因此一樣可以透過解構賦值的方式,把想要的資料取出:
整個流程會像這樣:

如果你對於 props 還不是這麼熟悉的話,也可以在 <CardFooter /> 中透過 console.log(props) 把它呈現出來看一下。
換你了:在 CardFooter 取得 App 的 inputValue#
現在輪到你練習把 App 中的狀態 inputValue 透過 props 傳遞到 CardFooter 中,實做的流程會像是這樣:
- 在 App 中透過 html 標籤的方式把
inputValue傳到 CardFooter 元件 - 在 CardFooter 中,透過函式參數的方式,取得 App 傳進來的 props
- 在 CardFooter 中透過
console.log(props)確認有得到 props
根據 inputValue 改變 CardFooter 的樣式#
現在我們已經可以在 CardFooter 取得 App 中的資料狀態,最後要來根據這個 inputValue 搭配前一章說明的條件轉譯和動態 CSS 樣式來讓 CardFooter 可以動態改變。
這裡的邏輯會是這樣:
- 當
inputValue沒有輸入時,Footer 會顯示---,顏色會是#d3d8e2 - 當
inputValue小於 15 時,Footer 會顯示SLOW,顏色會是#ee362d - 當
15 <= inputValue < 40,Footer 會顯示GOOD,顏色會是#1b82f1 - 當
inputValue大於等於 40 時,Footer 會顯示FAST,顏色會是#13d569
這裡我們可以使用 if...else...else if 做出類似的判斷:
接著在最後 return JSX 的地方,把對應的背景顏色和標題帶進去就可以了:
完成後,當使用者輸入的數字不同時,CardFooter 就會對應出現不同的文字內容和顏色:

換你了:根據 inputValue 改變 CardFooter 的文字內容和樣式#
在已經取得 App 中的 inputValue 後,要請你根據 inputValue 來讓 CardFooter 顯示不同的內容和背景樣式,類似的流程如下:
- 建立判斷
inputValue來顯示不同內容和背景樣式的邏輯 - 將判斷後的結果以變數和 style 的方式帶入 JSX 中
本單元相關之網頁連結、完整程式碼與程式碼變更部分可於 pass-props-to-components 分支檢視:https://github.com/pjchender/learn-react-from-hooks-internet-speed-converter/tree/pass-props-to-components
