MUKI AI Summary
使用 React Context API 可以輕鬆實現跨組件傳值功能,適合不需要複雜狀態管理的小型應用。與 Vue 的 Vite + Pinia 類似,React 提供多種狀態管理選擇,如 Redux、Mobx、Zustand、Recoil 和 Jotai,其中 Context API 是內建的選項,無需額外安裝套件。本文介紹了如何在 React 中利用 Context API 來傳遞會員資料,通過建立 UserContext 並在 App 中使用 UserProvider 來共享資料,確保在不同組件間能夠輕鬆取得使用者資料。
實作過程包括在獨立的 context 檔案中打 API 取得即時會員資料,並使用 createContext 和 useContext 建立資料共享機制。在 App 組件中引入 UserProvider,然後在內部使用 useUser Hook 來讀取和渲染使用者資料。此外,其他頁面如 Home.jsx 也可以通過 useUser 獲取資料,實現簡單而有效的跨組件資料傳遞。這種方法適合需要跨組件傳遞資料但不需要複雜狀態管理的情況。...
需求
現在如果使用 Vue 開發網站,我會習慣用 Vite + Pinia 幫我實現狀態管理與跨組件傳值的功能。
至於 React 也有蠻多選擇,較知名的是 Redux,以下是幾個常見的 Library:
- Redux
Redux 是一個非常流行的狀態管理 Library,用於管理應用的全域狀態。你可以將應用的狀態儲存在一個全域儲存中,並通過connect
高階元件來連接 React 元件。Redux 較適用於大型應用。 - Mobx
Mobx 是另一個流行的狀態管理庫,它使用可觀察對象和響應式機制來管理狀態。它可以更簡單地實現狀態管理,適用於中小型應用。 - React Context API
React 內建的 Context API 允許你建立全域的上下文,以便跨元件傳遞資料。雖然它不如 Redux 或 Mobx 強大,但對於小型應用和簡單的跨元件資料傳遞來說非常足夠。 - Zustand
Zustand 是一個小巧的狀態管理庫,專門為 React 設計。它使用 Hooks 和 Context API,讓你能夠方便地管理狀態,適用於中小型應用。 - Recoil
Recoil 是由 Facebook 開發的狀態管理庫,它專為 React 設計。提供了一種簡單的方式來管理元件之間的狀態,並且支援原子狀態管理。 - Jotai
Jotai 是另一個小型的狀態管理庫,使用了 React Hooks 和 Context。它的設計非常簡單,易於理解和使用。(Jotai 是「狀態」的拼音,非常粗暴好理解 😂)
因為我的需求非常簡單,只是要跨組件傳遞會員資料,不需要用到狀態管理,因此我選擇的方法是「React Context API」,不需要額外安裝套件,直接使用 React API 即可。
實作的功能與流程為:使用者切換路由時,都會先打一隻 /me
的 api 取得即時的會員資料與權限,我再用這些資料,顯示會員基本資料以及做權限控管。
使用 Context API 建立資料
首先,我們要把「打 /me
API」這件事情,放在一個獨立的 context 檔案中
▼ 先新增檔案:src/context/UserContext.js
,再用 crateContext
以及 useContext
建立並儲存資料
import React, { createContext, useContext, useState, useEffect } from 'react' import { getUserApi } from '../api/auths' const UserContext = createContext() export const useUser = () => { return useContext(UserContext) } export const UserProvider = ({ children }) => { const [loading, setLoading] = useState(true) const [user, setUser] = useState({}) useEffect(() => { async function fetchUser() { try { const res = await getUserApi() setUser(res.data) setLoading(false) } catch (error) { console.error('Response error:', error) } } fetchUser() }, []) return ( <UserContext.Provider value={user}> {/* 使用 loading 來判斷是否已經取得使用者資料,如果還沒取得,則不顯示 children */} {loading ? null : children} </UserContext.Provider> ) }
使用 Provider 共享 User 資料
▼ 打開 App.jsx,匯入 UserProvider
import { UserProvider } from './context/UserContext' const App = () => { return ( // 使用 UserProvider,跨組件傳遞 user 資料 <UserProvider> <AppContent /> </UserProvider> ) }
在 App.jsx 讀取 User 資料
▼ 我們可以用剛剛的 useUser
讀到 User 資料,寫法如下
import { UserProvider, useUser } from './context/UserContext' const App = () => { const user = useUser() return ( <UserProvider> // 這邊處理取得的 user 資料 </UserProvider> ) }
但這樣寫 user 會是 undefined
,原因是我們在 <UserProvider>
設定之前,就讀取了 useUser
,因此 user 為 undefined
▼ 所以比較好的寫法,是在 <UserProvider>
內部使用 useUser
Hook,改寫如下
import { UserProvider, useUser } from './context/UserContext' const App = () => { return ( <UserProvider> <AppContent /> </UserProvider> ) } const AppContent = () => { const user = useUser() return ( // 處理並渲染 user 資料 ) }
在其他頁面讀取 User 資料
假設我們有一頁 Home.jsx 也要讀取使用者資料,只要使用 useUser
就能輕鬆取得
import { useUser } from './context/UserContext' const Home = () => { const user = useUser() return ( // 處理並渲染 user 資料 ) }
寫法就跟前面一樣,方便易懂好上手。
如果只是想要單純傳值,不需要複雜的狀態管理,可以考慮使用內建的 Context API,簡單解決煩惱!