ReactJS - 使用 useContext



Context 是 React 中一個重要的概念。它提供了一種能力,可以將資訊從父元件傳遞給其所有子元件,直到任何巢狀級別,而無需在每個級別透過 props 傳遞資訊。Context 將使程式碼更具可讀性和易於理解。Context 可用於儲存不更改或更改最少的資訊。Context 的一些用例如下:

  • 應用程式配置

  • 當前已認證使用者資訊

  • 當前使用者設定

  • 語言設定

  • 應用程式/使用者主題/設計配置

React 提供了一個特殊的 hook,useContext,用於在函式元件中訪問和更新上下文資訊。讓我們在本節中學習上下文及其相應的 hook。

Context 如何工作?

在瞭解 useContext hook 之前,讓我們回顧一下 Context 的基本概念以及它的工作原理。Context 有四個部分,

  • 建立一個新的上下文

  • 在根元件中設定上下文提供者

  • 在我們需要上下文資訊的元件中設定上下文消費者

  • 訪問上下文資訊並在渲染方法中使用它

讓我們建立一個應用程式來更好地理解 Context 及其用法。讓我們為在應用程式根元件中維護主題資訊建立一個全域性上下文,並在我們的子元件中使用它。

首先,使用以下命令建立並啟動一個應用程式:

create-react-app myapp
cd myapp
npm start

接下來,在 components 資料夾下建立一個元件 HelloWorld(src/components/HelloWorld.js)

import React from "react";
import ThemeContext from "../ThemeContext";
class HelloWorld extends React.Component {
   render() {
      return <div>Hello World</div>
   }
}
export default HelloWorld

接下來,建立一個新的上下文 (src/ThemeContext.js) 來維護主題資訊。

import React from 'react'
const ThemeContext = React.createContext({
   color: 'black',
   backgroundColor: 'white'
})
export default ThemeContext

這裡,

  • 使用 React.createContext 建立了一個新的上下文。

  • 上下文被建模為一個包含樣式資訊的的物件。

  • 設定文字顏色和背景的初始值。

接下來,透過包含 HelloWorld 元件和帶有主題上下文初始值的主題提供程式來更新根元件 App.js

import './App.css';
import HelloWorld from './components/HelloWorld';
import ThemeContext from './ThemeContext'
function App() {
   return (
      <ThemeContext.Provider value={{
         color: 'white',
         backgroundColor: 'green'
      }}>
      <HelloWorld />
      </ThemeContext.Provider>
   );
}
export default App;

這裡,使用了 ThemeContext.Provider,它是一個非視覺元件,用於設定要在其所有子元件中使用的主題上下文的值。

接下來,在 HelloWorld 元件中包含一個上下文消費者,並使用 HelloWorld 元件中的主題資訊來設定 hello world 訊息的樣式。

import React from "react";
import ThemeContext from "../ThemeContext";
class HelloWorld extends React.Component {
   render() {
      return  (
         <ThemeContext.Consumer>
         {
            ( {color, backgroundColor} ) =>
            (<div style={{
               color: color,
               backgroundColor: backgroundColor }}>
               Hello World
            </div>)
         }
      </ThemeContext.Consumer>)
   }
}
export default HelloWorld

這裡我們有,

  • 使用了 ThemeContext.Consumer,它是一個非視覺元件,提供對當前主題上下文詳細資訊的訪問

  • 使用函式表示式在 ThemeContext.Consumer 內部獲取當前上下文資訊

  • 使用物件解構語法獲取主題資訊並將值設定為 colorbackgroundColor 變數。

  • 使用主題資訊透過 style props 設定元件的樣式。

最後,開啟瀏覽器並檢查應用程式的輸出

ReactJS Using UseContext

useContext 的簽名

useContext 的簽名如下:

let contextValue = useContext( <contextName> )

這裡,

  • contextName 指的是要訪問的上下文的名稱。

  • contextValue 指的是所引用上下文的當前值。

使用 hook 訪問上下文的示例程式碼如下:

const theme = useContext(ThemContext)

透過 hook 使用 Context

讓我們更新我們的應用程式並使用上下文 hook 而不是上下文消費者。

首先,將 HelloWorld 元件轉換為函式元件。

import React from "react";
function HelloWorld() {
   return <div>Hello World</div>
}
export default HelloWorld

接下來,透過 useContext hook 訪問上下文的當前值

import React, { useContext } from "react"
import ThemeContext from '../ThemeContext'
function HelloWorld() {
   let theme = useContext(ThemeContext)
   return <div>Hello World</div>
}
export default HelloWorld

接下來,更新渲染函式以使用透過上下文獲取的主題資訊。

import React, { useContext } from "react"
import ThemeContext from '../ThemeContext'
function HelloWorld() {
   let theme = useContext(ThemeContext)
   return (
      <div style={{
         color: theme.color,
         backgroundColor: theme.backgroundColor }}>
            Hello World
      </div>
   )
}
export default HelloWorld

這裡我們有,

  • 使用 useContext 訪問 ThemeContext 上下文資訊。

  • 使用 ThemeContext 資訊設定文字的背景顏色和顏色。

最後,開啟瀏覽器並檢查應用程式的輸出。

Context Usage Through Hook

更新 Context

在某些情況下,更新上下文資訊是必要的。例如,我們可以提供一個選項讓使用者更改主題資訊。當用戶更改主題時,上下文應該更新。更新上下文將重新渲染所有子元件,這將更改應用程式的主題。

React 提供了一個選項,可以使用 useStateuseContext hook 來更新上下文。讓我們更新我們的應用程式以支援主題選擇。

首先,更新根元件 App.js 並使用 useState hook 來管理主題資訊,如下所示:

import './App.css'
import { useState } from 'react'
import HelloWorld from './components/HelloWorld'
import ThemeContext from './ThemeContext'
function App() {
   let initialTheme = {
      color: 'white',
      backgroundColor: 'green'
   }
   const [theme, setTheme] = useState(initialTheme)
   return (
      <ThemeContext.Provider value={{ theme, setTheme }}>
         <HelloWorld />
      </ThemeContext.Provider>
   );
}
export default App;

這裡我們有,

  • 使用 useState hook 在根元件的狀態中設定主題資訊。

  • 主題更新函式 useTheme 也作為主題資訊的一部分包含在上下文中。

接下來,更新 HelloWorld 元件以獲取儲存在上下文中的主題資訊。

import React, { useContext } from "react"
import ThemeContext from '../ThemeContext'
function HelloWorld() {
   let { theme, setTheme } = useContext(ThemeContext)
   return (<div style={{
            color: theme.color,
            backgroundColor: theme.backgroundColor }}>
         <div>Hello World</div>
      </div>)
}
export default HelloWorld

接下來,為使用者提供一個透過下拉選項更改主題的選項。

import React, { useContext } from "react"
import ThemeContext from '../ThemeContext'
function HelloWorld() {
   let { theme, setTheme } = useContext(ThemeContext)
   return (<div style={{
      color: theme.color,
      backgroundColor: theme.backgroundColor }}>
   <div>
      <select value={theme.backgroundColor}>
         <option value="green">Green</option>
         <option value="red">Red</option>
      </select>
      <div>Hello World</div>
   </div>)
}
export default HelloWorld

這裡我們有,

  • 添加了一個帶有兩個選項(綠色和紅色)的下拉框。

  • 使用當前主題值 value={theme.backgroundColor) 設定下拉框的當前值。

接下來,每當使用者透過 onChange 事件更改主題時,更新上下文。

import React, { useContext } from "react"
import ThemeContext from '../ThemeContext'
function HelloWorld() {
   let { theme, setTheme } = useContext(ThemeContext)
   return (<div style={{
      color: theme.color,
      backgroundColor: theme.backgroundColor }}>
   <div>
      <select value={theme.backgroundColor}
         onChange = {
            (e) => {
               setTheme({
                  ...theme,
                  backgroundColor: e.target.value
               })
            }} >
         <option value="green">Green</option>
         <option value="red">Red</option>
      </select>
   </div>
      <div>Hello World</div>
   </div>)
}
export default HelloWorld

這裡我們有,

  • onChange 事件附加到下拉框。

  • 在事件處理程式內部使用 setTheme 函式並將主題的背景顏色更新為使用者選擇的顏色。

根元件和 HelloWorld 元件的完整程式碼如下:

import React, { useContext } from "react"
import ThemeContext from '../ThemeContext'
function HelloWorld() {
   let { theme, setTheme } = useContext(ThemeContext)
   return (<div style={{
      color: theme.color,
      backgroundColor: theme.backgroundColor }}>
   <div>
      <select value={theme.backgroundColor}
         onChange= {
            (e) => {
               setTheme({
                  ...theme,
                  backgroundColor: e.target.value
               })
            }
         } >
         <option value="green">Green</option>
         <option value="red">Red</option>
      </select>
   </div>
      <div>Hello World</div>
   </div>)
}
export default HelloWorld

接下來,開啟瀏覽器並檢查應用程式。

Updating Context

當用戶選擇不同的背景顏色時,它將更新上下文,並因此重新渲染元件,並使用新的主題,如下所示:

Updating Context

總結

Context 降低了在 React 應用程式中維護全域性資料的複雜性。Context hook 透過簡化訪問和更新(透過 useState)上下文進一步降低了複雜性。

廣告