iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
Modern Web

前端開發之那些我會的與我不會的技術系列 第 17

React中使用useContext傳遞資料

  • 分享至 

  • xImage
  •  

在React如果要在組件之間傳遞資料可以使用props,用起來就像是呼叫帶入參數的函式。

function Content({text}) { // 使用解構將物件裡的text取出來
	return <p>{ text } </p>
}

function App() {
	return <Content text={'你好'} />
}

這種方式較適用於層級距離沒有太遠的組件,如果要傳遞資料的兩個組件之間距離很遠,中間要經過很多組件,這些組件又用不到這些資料,就可以考慮使用useContext來代替一層一層又一層層往下傳的props,包裹在最外層就可以讓底下的樹狀結構都可以使用context的值。

使用

使用createContext建立一個context並且export出去。

import { createContext } from "react";

export const TextContext = createContext('預設值');

將context包裹在外層,並帶入value,在這之下的子層都可以讀取這個value。

import { TextContext } from "./context/textContent";
function App() {

  return (
      <TextContext.Provider value={"Hello"}>
        <Content />
      </TextContext.Provider>
  );
}
export default App;

在要讀取的組件使用useContext,並帶入createContext的context

import { useContext } from "react";
import { TextContext } from "./context/textContent";
function ChildContent() {
  const text = useContext(TextContext);
  return <p>{text}</p>
}
export default ChildContent;

也可以這樣寫,把context的provider寫成一個組件方便使用,也把狀態都隔離出來放在這個context的組件裡面。

import { createContext } from "react";

export const TextContext = createContext();

export default function TextContextProvider({children}) {
  return (
    <TextContext.Provider value={'Hello'}>
      {children}
    </TextContext.Provider>
  )
}

會讀取最靠近的context

如果有多個context包裹著,讀到的值會是最靠近的context。以下的範例會建立一個context,然後重複使用並且一層一層包裹下去。如下圖,會有3個context然後分別帶入不同value,讓底下的Level組件讀取context的value決定字體大小。
https://ithelp.ithome.com.tw/upload/images/20231002/20162751WudqG2lmUQ.png
首先,還是建立一個context

import { createContext } from "react";

export const LevelContext = createContext();

建立一個Section組件,組件裡使用剛才建立的context並且包裹著children和Level組件

import { LevelContext } from "./levelContext";
import Level from "./Level";
function Section({children ,level}) {
  return <LevelContext.Provider value={level}>
    <Level />
    {children}
  </LevelContext.Provider>
}
export default Section;

Level組件使用剛才建立的LevelContext

import { useContext } from "react";
import { LevelContext } from "./levelContext";
function Level() {
  const level = useContext(LevelContext);
  const content = '哈囉';
  if (level === 1) {
    return <h1>{ content }</h1>
  }
  if (level === 2) {
    return <h2>{ content }</h2>
  }
  return <h3>{ content }</h3>
}

export default Level;

在Section組件帶入不同的level

import Section from "./context/section";
function App() {
  return (
    <Section level={1}>
      <Section level={2}>
        <Section level={5} />
      </Section>
    </Section>
  )
}

結果如下圖,context的value會讀取到最接近。
https://ithelp.ithome.com.tw/upload/images/20231002/20162751qg7wDpYD6b.png

不只用在字串或數字

context的value不只可以用字串或是數字,也可以把useState或是useReducer當作value將setter function或是dispatch供其他的組件共用。

使用typescript

在createContext後代入型別,因為default value可能會是null所以這邊給他或null的type。

type LevelValue = number | null
export const LevelContext = createContext<LevelValue>(null);

參考

https://react.dev/learn/passing-data-deeply-with-context

https://react.dev/reference/react/useContext

https://react.dev/learn/typescript


上一篇
React中的useReducer Hook:簡單解釋和範例
下一篇
Redux與useReducer + useContext:選擇適合你的狀態管理工具
系列文
前端開發之那些我會的與我不會的技術31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言