前言
前面章節我們有初步認識到了 React 元件傳遞過程也就是 Props,但 Props 通常是上層一路傳遞到下層,雖然這樣子可以確保資料流向,因為是單向的,但卻也會延生一些麻煩問題發生,也就是傳遞太深,因此這時候我們就要來認識一個新的東西 useContext。
Props 資料傳遞
就一般開發來講,我們大多都會使用 Props 將資料往下傳遞,所以讓我們用一張圖快速回顧一下前面章節 Props 的傳遞過程
props
我們可以從上方圖片發現 Props 必須傳遞三次才能夠將資料傳給 Button,這樣子在開發與維護上都會發生一定程度的困擾,例如:我們不確定 List 元件是不是根本不用接收 Props,但為了將資料傳遞給 Button 被迫要去接收 Props 等問題發生,因此我們在實務開發上其實很常會需要使用到跨元件溝通的。
那麼這邊就讓我們看一個實際的範例程式碼好了,或許這樣子會更有感覺?
底下是一個範例程式碼的舉例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| const Button = ({ data }) => { const pay = () => { window.alert(`你已成功購買 ${data.title}`); }
return ( <button type="button" onClick={ pay }>點我購買({ data.price } $)</button> ) }
const Card = ({ data }) => { return ( <div> <h5>產品名稱:{ data.title }</h5> <Button data={ data }/> </div> ) }
const Products = () => { const [ data, setData ] = React.useState({ title: 'PlayStation5', price: 75000, });
return ( <div> <ul> <li key={ data.title }> <Card data={ data } /> </li> </ul> </div> ) }
const App = () => { return ( <div> <Products /> </div> ) }
const app = document.querySelector('#app'); const root = ReactDOM.createRoot(app); root.render(<App />);
|
我們可以看到範例中 Card 只會使用到 title,但因為 Button 需要使用到 title 與 price 的關係,所以我們被迫要整包資料往下傳遞才能給 Button 使用,這樣會讓我們不經意的傳遞了非常多資料,而導致資料流會越來越龐大且複雜,那麼這時候我們就會需要一個東西,也就是跨元件溝通的技巧,也是我們這一章節要介紹的東西 useContext。
useContext
要使用 useContext 之前我們必須先認識一個東西也就是 createContext,在實作跨元件溝通時,我們一開始會需要使用 createContext 來建立一個 Context Object,因為 useContext 只能接受 Context Object 才能夠正常運作
1
| const DataContext = React.createContext();
|
這邊請切記 useContext 只能接受 Context Object 這件事情
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const DataContext = React.createContext();
const App = () => { const data = useContext(DataContext);
const data = useContext('DataContext');
const data = useContext();
const data = useContext(DataContext.Provider); return ( <div> </div> ) }
const app = document.querySelector('#app'); const root = ReactDOM.createRoot(app); root.render(<App />);
|
那麼使用 createContext 建立之後主要有兩個核心東西會使用
Provider
Consumer
- 接收資料用,會搭配一個
value 屬性,但這一個實際上會被 useContext 取代。
接下來該怎麼使用呢?首先 createContext 本身也是 React 元件一種,因此只需要在元件外層使用 DataContext 包覆並且加上預計要跨元件傳遞的值,並稍微調整一下 Card 的部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| const Card = ({ data }) => { return ( <div> <h5>產品名稱:{ data.title }</h5> <Button/> </div> ) }
const Products = () => { const [ data, setData ] = React.useState({ title: 'PlayStation5', price: 75000, });
return ( <DataContext.Provider value={ data }> <ul> <li key={ data.title }> <Card data={ data } /> </li> </ul> </DataContext.Provider> ) }
|
那麼 value 概念也類似於 props。
接著要改寫 Button 並改成使用 useContext 來接收資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
const Button = () => { const data = React.useContent(DataContext); const pay = () => { window.alert(`你已成功購買 ${data.title}`); }
return ( <button type="button" onClick={ pay }>點我購買({ data.price } $)</button> ) }
|
這樣子就可以做跨元件傳遞了,你可以發現 Button 不再透過 Props 方式接收而是透過 useContext 來接收並取代。
接著讓我們看一張圖了解一下目前資料是怎麼傳遞的
value
透過上方圖片我們可以看到資料直接跨過了 Card 傳遞到 Button 元件。
而這個概念基本上與 Vue 的 Provide / Inject 非常雷同,你可以隨時自己決定何時要 Inject,在後面我們會來進入一些簡單的開發,讓前面知識點可以貫穿起來。
這邊有一個小小注意事項要注意,使用 Provider 的時候它能接收的只有 value,若你改成 data={ data } 反而是無法傳遞的唷。
後記
本文將會同步更新到我的部落格