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