一、Context API 深度應用
1. 核心實現原理
通過createContext
創建上下文對象,使用Provider組件包裹需要共享狀態的組件樹,子組件通過useContext
?Hook或Consumer組件消費數據。
代碼示例(主題切換場景):
// 創建上下文(帶類型定義)
type ThemeContextType = {theme: 'light' | 'dark';toggleTheme: () => void;
};const ThemeContext = createContext<ThemeContextType | null>(null);// Provider組件封裝
export const ThemeProvider = ({ children }) => {const [theme, setTheme] = useState<'light' | 'dark'>('light');// 使用useCallback避免重復渲染const toggleTheme = useCallback(() => {setTheme(prev => prev === 'light' ? 'dark' : 'light');}, []);// 使用useMemo優化對象引用const value = useMemo(() => ({ theme, toggleTheme }), [theme]);return (<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>);
};// 消費組件
const ThemeButton = () => {const context = useContext(ThemeContext);if (!context) throw new Error("Missing ThemeProvider");return (<button style={{ background: context.theme === 'dark' ? '#333' : '#fff',color: context.theme === 'dark' ? '#fff' : '#333'}}onClick={context.toggleTheme}>Toggle Theme</button>);
};
最佳實踐:
- 類型安全:結合TypeScript定義上下文類型
- 性能優化:使用
useMemo
/useCallback
避免無效渲染 - 錯誤邊界:強制Provider包裹檢查
- 模塊化:按業務域拆分多個Context
二、Redux 現代工程實踐
1. 架構演進
推薦使用Redux Toolkit(RTK)簡化傳統Redux的模板代碼,結合React-Redux實現高效狀態管理。
代碼示例(計數器場景):
// store.ts
import { configureStore, createSlice } from '@reduxjs/toolkit';const counterSlice = createSlice({name: 'counter',initialState: { value: 0 },reducers: {increment: state => { state.value += 1 },decrement: state => { state.value -= 1 },incrementBy: (state, action: PayloadAction<number>) => {state.value += action.payload}}
});export const store = configureStore({reducer: {counter: counterSlice.reducer}
});// App.tsx
import { Provider } from 'react-redux';
import { useAppSelector, useAppDispatch } from './hooks';const CounterDisplay = () => {const count = useAppSelector(state => state.counter.value);return <div>{count}</div>;
};const CounterControls = () => {const dispatch = useAppDispatch();return (<><button onClick={() => dispatch(counterSlice.actions.increment())}>+</button><button onClick={() => dispatch(counterSlice.actions.decrement())}>-</button></>);
};
核心優勢:
- 不可變數據管理(通過Immer實現)
- 中間件支持(Redux-Thunk/Saga)
- 時間旅行調試(Redux DevTools)
- 類型安全(TypeScript深度集成)
三、選型決策樹
維度 | Context API | Redux |
---|---|---|
適用場景 | 中小型應用/局部狀態共享 | 大型復雜應用/全局狀態管理 |
學習曲線 | 低(React內置) | 中高(需掌握中間件等概念) |
性能優化 | 需手動優化 | 內置性能優化 |
調試能力 | 基礎React DevTools | 時間旅行調試 11 |
異步處理 | 需結合useEffect/自定義Hook | 內置中間件支持 |
四、工程化建議
-
?狀態分層策略
- 組件級:
useState
/useReducer
- 模塊級:Context API
- 應用級:Redux
- 服務級:React Query/SWR
- 組件級:
-
?性能優化要點
- Context:拆分高頻/低頻更新Context
- Redux:使用
reselect
創建記憶化selector - 通用:避免在渲染函數中創建新對象
-
?代碼規范
// Bad: 直接傳遞新對象導致無效渲染 <MyContext.Provider value={{ theme, toggleTheme }}>// Good: 使用useMemo優化 const value = useMemo(() => ({ theme, toggleTheme }), [theme])
-
?錯誤處理
- 添加狀態變更日志
- 使用Redux中間件統一錯誤處理
- 實現Context兜底默認值
五、常見陷阱及解決方案
-
?Context渲染風暴
- 現象:Provider值變化導致所有消費者重新渲染
- 方案:拆分Context / 使用
memo
-
?Redux狀態冗余
- 現象:store中存儲非全局狀態
- 方案:遵循最小狀態原則
-
?異步狀態競爭
// 使用AbortController取消過期請求 const fetchUser = createAsyncThunk('user/fetch',async (userId, { signal }) => {const response = await fetch(`/users/${userId}`, { signal });return response.json();} );
在工程實踐中,建議:
- 中小型項目優先使用Context API + TypeScript
- 復雜應用采用Redux Toolkit + RTK Query
- 混合方案:Redux管理核心業務流,Context處理UI狀態
最終選型需綜合考慮項目規模、團隊經驗和長期維護成本。對于新項目,可以從Context API起步,隨著復雜度增長逐步引入Redux。