React18+TypeScript状态管理最佳实践
目录
一、核心概念与流程
1. createContext 的作用
2. useContext 的作用
二、在 Ant Design Pro v6 中的实现步骤
1. 封装 Provider 组件
2. 集成到全局布局
3. 组件中消费状态
三、性能优化技巧
1. 避免无效渲染
2. 自定义 Hook 封装
四、常见场景与避坑指南
1. 典型应用场景
2. 关键注意事项
五、完整案例:主题切换实现
总结
在 Ant Design Pro v6(基于 Umi 4 + React 18+)与 TypeScript 中,createContext
和 useContext
是管理跨组件状态的核心工具。以下是结合最佳实践的系统指南:
一、核心概念与流程
1. createContext
的作用
创建上下文对象,包含 Provider
(提供数据)和 Consumer
(消费数据,已被 useContext
替代)。
- TypeScript 强类型定义:避免运行时错误,明确上下文结构:
// src/contexts/UserContext.ts import { createContext } from 'react';interface UserContextType {name: string;role: 'admin' | 'user';setUser: (user: Partial<UserContextType>) => void; }export const UserContext = createContext<UserContextType | null>(null);
2. useContext
的作用
在函数组件中消费上下文值,避免逐层传递 props:
const userContext = useContext(UserContext);
if (!userContext) throw new Error('未在 Provider 内使用!');
return userContext;
二、在 Ant Design Pro v6 中的实现步骤
1. 封装 Provider 组件
在 /src/contexts
目录下创建 Provider,结合 useState
或 useReducer
管理状态:
// src/contexts/UserProvider.tsx
import { ReactNode, useState } from 'react';
import { UserContext } from './UserContext';export default ({ children }: { children: ReactNode }) => {const [user, setUser] = useState({ name: '', role: 'user' });const contextValue = {...user,setUser: (updates: Partial<UserContextType>) => setUser(prev => ({ ...prev, ...updates }))};return (<UserContext.Provider value={contextValue}>{children}</UserContext.Provider>);
};
2. 集成到全局布局
在 src/app.tsx
中包裹全局组件,确保所有页面可访问上下文:
// src/app.tsx
import UserProvider from '@/contexts/UserProvider';export function rootContainer(container: ReactNode) {return <UserProvider>{container}</UserProvider>;
}
3. 组件中消费状态
直接通过 useContext
获取数据或更新函数:
// src/pages/Profile/index.tsx
import { UserContext } from '@/contexts/UserContext';export default () => {const { name, setUser } = useContext(UserContext)!;return (<Button onClick={() => setUser({ name: 'Admin' })}>更新用户:{name}</Button>);
};
三、性能优化技巧
1. 避免无效渲染
- 拆分上下文:将频繁变更的状态(如用户输入)与静态数据(如配置)分离。
const UserConfigContext = createContext<ConfigType>(null!); const UserStateContext = createContext<StateType>(null!);
- 缓存
value
对象:使用useMemo
减少重渲染:const contextValue = useMemo(() => ({ user, setUser }), [user]);
2. 自定义 Hook 封装
提供类型安全提示,简化调用:
// src/hooks/useUser.ts
export default () => {const context = useContext(UserContext);if (!context) throw new Error('UserContext 未初始化');return context;
};
四、常见场景与避坑指南
1. 典型应用场景
- 用户身份认证状态
- 主题切换(深色/浅色模式)
- 多语言国际化(结合
umi-plugin-locale
) - 全局弹窗/通知控制
2. 关键注意事项
- 默认值问题:未包裹
Provider
时返回createContext
的默认值,需做好错误处理。 - 嵌套顺序:内层
Provider
会覆盖外层同名Context
。 - 异步更新:在
useEffect
中更新上下文时,需考虑依赖项避免死循环。
五、完整案例:主题切换实现
// 1. 定义主题上下文
const ThemeContext = createContext<{theme: 'light' | 'dark';toggleTheme: () => void;
} | null>(null);// 2. 创建 Provider
export const ThemeProvider = ({ children }) => {const [theme, setTheme] = useState<'light' | 'dark'>('light');const toggleTheme = () => setTheme(t => t === 'light' ? 'dark' : 'light');const value = useMemo(() => ({ theme, toggleTheme }), [theme]);return (<ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>);
};// 3. 在组件中使用
const ThemeButton = () => {const { theme, toggleTheme } = useContext(ThemeContext)!;return (<Button onClick={toggleTheme}>当前主题:{theme}</Button>);
};
总结
在 Ant Design Pro v6 + TypeScript 技术栈中:
- 强类型定义是基础,避免空值错误;
- Provider 全局挂载确保跨组件共享状态;
- 性能优化优先考虑上下文拆分与
useMemo
; - 自定义 Hook 提升代码复用率与可维护性。
通过上下文管理轻量级全局状态,可减少对 Redux 的依赖,保持项目简洁性。