iT邦幫忙

2022 iThome 鐵人賽

DAY 9
0
Modern Web

終究都要學 React 何不現在學呢?系列 第 9

終究都要學 React 何不現在學呢? - React 基礎 - useContext - (9)

  • 分享至 

  • xImage
  •  

前言

前面章節我們有初步認識到了 React 元件傳遞過程也就是 Props,但 Props 通常是上層一路傳遞到下層,雖然這樣子可以確保資料流向,因為是單向的,但卻也會延生一些麻煩問題發生,也就是傳遞太深,因此這時候我們就要來認識一個新的東西 useContext。

Props 資料傳遞

就一般開發來講,我們大多都會使用 Props 將資料往下傳遞,所以讓我們用一張圖快速回顧一下前面章節 Props 的傳遞過程

https://ithelp.ithome.com.tw/upload/images/20220922/20119486EN0ZqZ5e4s.png

我們可以從上方圖片發現 Props 必須傳遞三次才能夠將資料傳給 Button,這樣子在開發與維護上都會發生一定程度的困擾,例如:我們不確定 List 元件是不是根本不用接收 Props,但為了將資料傳遞給 Button 被迫要去接收 Props 等問題發生,因此我們在實務開發上其實很常會需要使用到跨元件溝通的。

那麼這邊就讓我們看一個實際的範例程式碼好了,或許這樣子會更有感覺?

底下是一個範例程式碼的舉例

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 />);

CodePen 連結

我們可以看到範例中 Card 只會使用到 title,但因為 Button 需要使用到 titleprice 的關係,所以我們被迫要整包資料往下傳遞才能給 Button 使用,這樣會讓我們不經意的傳遞了非常多資料,而導致資料流會越來越龐大且複雜,那麼這時候我們就會需要一個東西,也就是跨元件溝通的技巧,也是我們這一章節要介紹的東西 useContext

useContext

要使用 useContext 之前我們必須先認識一個東西也就是 createContext,在實作跨元件溝通時,我們一開始會需要使用 createContext 來建立一個 Context Object,因為 useContext 只能接受 Context Object 才能夠正常運作

const DataContext = React.createContext();

CodePen 連結

這邊請切記 useContext 只能接受 Context Object 這件事情

const DataContext = React.createContext();

const App = () => {
  // ✅ Good!符合 useContext 用法
  const data = useContext(DataContext);

  // ❌ Error!不符合 useContext 用法
  const data = useContext('DataContext');

  // ❌ Error!不符合 useContext 用法
  const data = useContext();

  // ❌ Error!不符合 useContext 用法
  const data = useContext(DataContext.Provider);
  return (
    <div>
    </div>
  )
}

const app = document.querySelector('#app');
const root = ReactDOM.createRoot(app);
root.render(<App />);

CodePen 連結

那麼使用 createContext 建立之後主要有兩個核心東西會使用

  • Provider
    • 傳遞資料用,會搭配一個 value 屬性。
  • Consumer
    • 接收資料用,會搭配一個 value 屬性,但這一個實際上會被 useContext 取代。

接下來該怎麼使用呢?首先 createContext 本身也是 React 元件一種,因此只需要在元件外層使用 DataContext 包覆並且加上預計要跨元件傳遞的值,並稍微調整一下 Card 的部分

// ...略
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>
  )
}
// ...略

CodePen 連結

那麼 value 概念也類似於 props

接著要改寫 Button 並改成使用 useContext 來接收資料

// ...略

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 來接收並取代。

CodePen 連結

接著讓我們看一張圖了解一下目前資料是怎麼傳遞的

https://ithelp.ithome.com.tw/upload/images/20220922/20119486hk5JLGdylg.png

透過上方圖片我們可以看到資料直接跨過了 Card 傳遞到 Button 元件。

而這個概念基本上與 Vue 的 Provide / Inject 非常雷同,你可以隨時自己決定何時要 Inject,在後面我們會來進入一些簡單的開發,讓前面知識點可以貫穿起來。

這邊有一個小小注意事項要注意,使用 Provider 的時候它能接收的只有 value,若你改成 data={ data } 反而是無法傳遞的唷。

後記

本文將會同步更新到我的部落格


上一篇
終究都要學 React 何不現在學呢? - React 基礎 - useEffect - (8)
下一篇
終究都要學 React 何不現在學呢? - React 基礎 - TodoList (上) - (10)
系列文
終究都要學 React 何不現在學呢?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言