useContext
useContext是React的一個Hook,用于在函數組件中訪問上下文(context)的值。它可以幫助我們在組件樹中共享狀態,而不需要通過props一層層傳遞
特點
- 用于跨組件共享狀態
- 需要配合React.createContext和Context.Provider使用
- 簡化了組件間的狀態傳遞
基本用法
- 創建 Context
import React, { createContext, useContext } from 'react';
const MyContext = createContext('默認值');
- 提供 Context值
const App = () => {return (// 這個value可以傳遞任何類型的數據,包括字符串、數組、對象、函數等<MyContext.Provider value="共享值"><Child /></MyContext.Provider>)
}
- 消費 Context值
const Child = () => {const value = useContext(MyContext)return <div>{value}</div>
}
注意事項
- useContext只能在函數組件或自定義Hook中使用,不能在類組件中使用
- 如果Context.Provider的value發生變化,所有使用該Context的組件都會重新渲染
- 如果沒有Provider包裹,useContext會返回createContext時定義的默認值
- 性能優化:如果value傳遞的是一個對象或數組,避免在每次渲染時創建新的引用(例如直接傳遞字面量對象或數組時),可以使用useMemo緩存value
const value = useMemo(() => ({name: 'John',age:30}), [])
- 嵌套Context:如果需要傳遞多個值,可以將他們組合成一個對象,或者使用多個Context.
使用場景
- 主題切換:在應用中實現亮色和暗色主題的切換
- 用戶認證:共享當前用戶的認證狀態,例如是否已登錄
- 多語言支持:根據用戶的語言偏好動態切換界面語言
- 全局狀態管理:在小型應用中替代Redux等狀態管理工具,簡化狀態共享
useReducer
useReducer是React的一個的Hook。用于在函數組件中進行更復雜的狀態管理。它適合于狀態邏輯較復雜、涉及多個子值或下一個狀態依賴于之前狀態的場景。用法類似于Redux的reducer
基本用法
import { useReducer } from 'react'
function reducer(state, action){switch(action.type){case 'increment':return { count: state.count + 1 }case 'decrement':return { count: state.count - 1 }default:throw new Error()}
}function Counter(){const [state, dispatch] = useReducer(reducer, {count: 0})return (<>Count: {state.count}// 通過dispatch 觸發action 的函數<button onClick={() => dispatch({ type: 'increment' })}>+</button><button onClick={() => dispatch({ type: 'decrement' })}>-</button></>)
}
1、render函數根據action.type來決定如何更新狀態
2、dispatch函數用于觸發狀態更新,每次點擊按鈕時,都會調用dispatch并傳遞相應的action對象
使用場景
- 復雜的狀態邏輯:當狀態更新邏輯較為復雜,或者需要根據前一個狀態來計算新狀態時,useReducer可以更好地組織代碼
- 多個子值:當狀態是一個包含多個子值的對象時,useReducer可以更方便管理這些子值
- 性能優化:在某些情況下,useReducer可以比useState更高效,因為它允許將狀態更新邏輯集中在一個地方,減少不必要的重復渲染
useContext和useReducer結合使用實現全局狀態管理(類似于Redux)
- useReducer管理全局狀態
- useContext提供和消費這個狀態
import React, { createContext, useReducer, useContext } from 'react'
const CountContext = createContext(null)
function reducer(state, action){switch(action.type){case 'add':return { count: state.count + 1 }default:return state}
}function ConterProvider({ children }){const [state, dispatch] = useReducer(reducer, {count: 0})return (<CountContext.Provider value={{state, dispatch}}>{ children }</CountContext.Provider>)
}function Counter(){const { state, dispatch } = useContext(CountContext)return (<button onClick={() => dispatch({ type: 'add' })}>Count: {state.count}</button>)
}// 使用
function App() {return (<CounterProvider><Counter /></CounterProvider>)
}