1. 基本概念
1.1 什么是 Context
Context 提供了一种在组件树中共享数据的方式,而不必通过 props 显式地逐层传递。它主要用于共享那些对于组件树中许多组件来说是"全局"的数据。
1.2 基本用法
jsx
// 1. 创建 Context
const ThemeContext = React.createContext('light');
// 2. 提供 Context
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
// 3. 消费 Context
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = React.useContext(ThemeContext);
return <button className={theme}>Themed Button</button>;
}
2. Context API 详解
2.1 创建 Context
jsx
// 创建 Context 并设置默认值
const UserContext = React.createContext({
name: 'Guest',
isAdmin: false
});
// 导出 Context 供其他组件使用
export default UserContext;
2.2 Provider 组件
jsx
function App() {
const [user, setUser] = useState({
name: 'John',
isAdmin: true
});
return (
<UserContext.Provider value={user}>
<div className="app">
<MainContent />
<Sidebar />
</div>
</UserContext.Provider>
);
}
2.3 消费 Context
使用 useContext Hook(推荐)
jsx
function UserProfile() {
const user = React.useContext(UserContext);
return (
<div>
<h2>User Profile</h2>
<p>Name: {user.name}</p>
<p>Role: {user.isAdmin ? 'Admin' : 'User'}</p>
</div>
);
}
使用 Consumer 组件
jsx
function UserRole() {
return (
<UserContext.Consumer>
{user => (
<span>
Role: {user.isAdmin ? 'Admin' : 'User'}
</span>
)}
</UserContext.Consumer>
);
}
3. 高级用法
3.1 多个 Context 组合
jsx
const ThemeContext = React.createContext('light');
const UserContext = React.createContext({ name: 'Guest' });
function App() {
return (
<ThemeContext.Provider value="dark">
<UserContext.Provider value={{ name: 'John' }}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
function Layout() {
const theme = React.useContext(ThemeContext);
const user = React.useContext(UserContext);
return (
<div className={theme}>
<header>Welcome, {user.name}</header>
<main>Content</main>
</div>
);
}
3.2 动态 Context
jsx
const ThemeContext = React.createContext({
theme: 'light',
toggleTheme: () => {}
});
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemeToggleButton() {
const { theme, toggleTheme } = React.useContext(ThemeContext);
return (
<button onClick={toggleTheme}>
Current theme: {theme}
</button>
);
}
3.3 Context 与 TypeScript
typescript
// 定义 Context 类型
interface UserContextType {
name: string;
isAdmin: boolean;
updateUser: (name: string) => void;
}
const UserContext = React.createContext<UserContextType | undefined>(undefined);
// 创建自定义 Hook
function useUser() {
const context = React.useContext(UserContext);
if (context === undefined) {
throw new Error('useUser must be used within a UserProvider');
}
return context;
}
// Provider 组件
function UserProvider({ children }: { children: React.ReactNode }) {
const [name, setName] = useState('Guest');
const [isAdmin] = useState(false);
const updateUser = (newName: string) => {
setName(newName);
};
return (
<UserContext.Provider value={{ name, isAdmin, updateUser }}>
{children}
</UserContext.Provider>
);
}
4. 最佳实践
4.1 创建自定义 Hook
jsx
// 创建自定义 Hook 封装 Context 逻辑
function useTheme() {
const context = React.useContext(ThemeContext);
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
// 使用自定义 Hook
function ThemedButton() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme} className={theme}>
Toggle Theme
</button>
);
}
4.2 分离 Context 逻辑
jsx
// contexts/theme.js
export const ThemeContext = React.createContext({
theme: 'light',
toggleTheme: () => {}
});
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const value = {
theme,
toggleTheme: () => setTheme(t => t === 'light' ? 'dark' : 'light')
};
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
const context = React.useContext(ThemeContext);
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
4.3 性能优化
jsx
// 使用 memo 避免不必要的重渲染
const UserInfo = React.memo(function UserInfo() {
const { name } = useUser();
return <div>User: {name}</div>;
});
// 分离状态,避免不相关的更新
function AppProvider({ children }) {
return (
<ThemeProvider>
<UserProvider>
<SettingsProvider>
{children}
</SettingsProvider>
</UserProvider>
</ThemeProvider>
);
}
5. 常见问题和解决方案
5.1 避免重渲染
jsx
// 使用 useMemo 优化 Context value
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const value = useMemo(() => ({
theme,
toggleTheme: () => setTheme(t => t === 'light' ? 'dark' : 'light')
}), [theme]);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}
5.2 处理嵌套 Context
jsx
// 创建组合 Provider
function AppProviders({ children }) {
return (
<AuthProvider>
<ThemeProvider>
<UserProvider>
{children}
</UserProvider>
</ThemeProvider>
</AuthProvider>
);
}
// 使用组合 Provider
function App() {
return (
<AppProviders>
<MainApp />
</AppProviders>
);
}
6. 总结
6.1 使用场景
- 主题切换
- 用户认证状态
- 语言偏好
- 全局配置
- 路由状态共享
6.2 最佳实践建议
- 适度使用 Context
- 创建专门的 Provider 组件
- 使用自定义 Hook 封装 Context 逻辑
- 注意性能优化
- 合理组织 Context 结构