讓我們看一個例子,DComponent
跟 FComponent
需要最頂層 AComponent
的狀態 name
,此時需要將狀態 name
一層一層地往下傳遞,我們稱之為 Prop Drilling,這樣做會有一個明顯的問題,多個層級傳遞屬性會導致程式碼變得複雜且難以閱讀。
function AComponent() {
const [name, setName] = useState("John");
return <BComponent name={name} />
}
// 沒有使用到 name 屬性,單純傳遞下去
function BComponent({ name }) {
return <CComponent name={name} />
}
// 沒有使用到 name 屬性,單純傳遞下去
function CComponent({ name }) {
return <DComponent name={name} />
}
// 有使用到 name 屬性
// 子元件 FComponent 也需要,所以繼續傳遞下去
function DComponent({ name }) {
return (
<>
<h1>{name}</h1>
<EComponent name={name} />
</>
);
}
// 沒有使用到 name 屬性,單純傳遞下去
function EComponent({ name }) {
return <FComponent name={name} />
}
// 有使用到 name 屬性
function FComponent({ name }) {
return <h1>{name}</h1>;
}
Context API 是 React 提供的一種解決方案,允許我們在整個應用程式中共享資料或狀態,而不必手動傳遞它們到每個元件,Context API 包含以下概念:
首先,我們使用 createContext
函式來創建一個自定義的 context(NameContext
),這個 context 將用於我們希望在多個元件之間共享的資料。
import { createContext } from "react";
const NameContext = createContext();
接下來,我們使用 NameContext.Provider
來包住我們希望共享資料的元件,value
屬性是想要共享的資料狀態,通常是包含狀態和函式的一個物件。
function AComponent() {
const [name, setName] = useState("John");
return (
<NameContext.Provider
value={{
name,
setName
}}
>
<BComponent />
</NameContext.Provider>
);
}
最後,在需要使用共享資料的元件中,透過 useContext
這一個 Hook 來讀取 context 中的資料,並且解構出我們需要的值,這樣子我們就不需要把 name
跟 setName
透過 props 一路從 AComponent
傳遞到 FComponent
了。
function FComponent() {
// useContext(NameContext) 回傳一個包含 name 和 setName 的物件,因此可以使用物件解構
const { name, setName } = useContext(NameContext);
return (
<>
<h1>{name}</h1>
<button type="button" onClick={() => setName("Mark")}>
Change Name
</button>
</>
);
}
當我們遇到在多層級的元件之間傳遞 props 時出現的 Prop Drilling 問題,Context API 是 React 提供的一種解決方案,透過建立共享的 context 和 provider,我們能夠更輕鬆地讀取和更新共享資料。