Context API是React提供的一种组件间通信机制,允许你将数据通过组件树传递,而无需在每个层级手动传递props。
import React, { createContext, useState } from 'react';
// 创建Context对象
const ThemeContext = createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export { ThemeContext, ThemeProvider };
import React from 'react';
import { ThemeProvider } from './ThemeContext';
import AppContent from './AppContent';
function App() {
return (
<ThemeProvider>
<AppContent />
</ThemeProvider>
);
}
export default App;
import React, { Component } from 'react';
import { ThemeContext } from './ThemeContext';
class ThemedButton extends Component {
static contextType = ThemeContext;
render() {
const { theme, toggleTheme } = this.context;
return (
<button
onClick={toggleTheme}
style={{
backgroundColor: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#000' : '#fff'
}}
>
切换主题
</button>
);
}
}
export default ThemedButton;
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
function ThemeToggle() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div className={`theme-toggle ${theme}`}>
<span>当前主题: {theme}</span>
<button onClick={toggleTheme}>
切换到 {theme === 'light' ? '深色' : '浅色'} 模式
</button>
</div>
);
}
export default ThemeToggle;
import React, { createContext, useContext } from 'react';
// 创建多个Context
const UserContext = createContext();
const SettingsContext = createContext();
// 提供多个Context
function AppProviders({ children }) {
const user = { name: 'John Doe', role: 'admin' };
const settings = { language: 'zh-CN', notifications: true };
return (
<UserContext.Provider value={user}>
<SettingsContext.Provider value={settings}>
{children}
</SettingsContext.Provider>
</UserContext.Provider>
);
}
// 在组件中使用多个Context
function UserProfile() {
const user = useContext(UserContext);
const settings = useContext(SettingsContext);
return (
<div>
<h3>用户信息</h3>
<p>姓名: {user.name}</p>
<p>角色: {user.role}</p>
<p>语言: {settings.language}</p>
<p>通知: {settings.notifications ? '开启' : '关闭'}</p>
</div>
);
}
除了useContext Hook,还可以使用Consumer组件(适用于React 16.3+):
import React from 'react';
import { ThemeContext } from './ThemeContext';
function ThemeDisplay() {
return (
<ThemeContext.Consumer>
{({ theme }) => (
<div className={`theme-display ${theme}`}>
<h3>当前主题: {theme}</h3>
<div className="theme-preview">
{theme === 'light' ? '🌞' : '🌙'}
</div>
</div>
)}
</ThemeContext.Consumer>
);
}
import React, { createContext, useState, useContext, useEffect } from 'react';
// 创建Context
const AuthContext = createContext();
// 创建Provider组件
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// 模拟从localStorage或API获取用户信息
const savedUser = localStorage.getItem('user');
if (savedUser) {
setUser(JSON.parse(savedUser));
}
setLoading(false);
}, []);
const login = async (username, password) => {
// 模拟登录API调用
const mockUser = {
id: 1,
username,
token: 'mock-jwt-token'
};
setUser(mockUser);
localStorage.setItem('user', JSON.stringify(mockUser));
};
const logout = () => {
setUser(null);
localStorage.removeItem('user');
};
const value = {
user,
loading,
login,
logout,
isAuthenticated: !!user
};
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
}
// 自定义Hook
export function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth必须在AuthProvider内使用');
}
return context;
}
// 受保护的路由组件
export function ProtectedRoute({ children }) {
const { isAuthenticated, loading } = useAuth();
if (loading) {
return <div>加载中...</div>;
}
if (!isAuthenticated) {
return <div>请先登录</div>;
}
return children;
}
import React, { memo, useContext } from 'react';
import { ThemeContext } from './ThemeContext';
const ExpensiveComponent = memo(function ExpensiveComponent() {
const { theme } = useContext(ThemeContext);
console.log('ExpensiveComponent渲染了');
// 模拟昂贵的计算
const expensiveResult = Array(1000)
.fill(null)
.map((_, i) => i)
.reduce((a, b) => a + b, 0);
return (
<div className={theme}>
计算结果: {expensiveResult}
</div>
);
});
export default ExpensiveComponent;
// 不好的做法:所有数据在一个Context中
const AppContext = createContext();
// 好的做法:按功能分离Context
const ThemeContext = createContext();
const UserContext = createContext();
const NotificationContext = createContext();
// 组件只订阅需要的Context
function UserProfile() {
const user = useContext(UserContext); // 只有user变化时才重新渲染
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Props | 父子组件简单通信 | 简单直观,类型检查 | props drilling问题 |
| Context API | 中大型应用,组件树深层共享 | React原生,无需额外依赖 | 频繁更新可能影响性能 |
| Redux | 复杂状态管理,需要时间旅行调试 | 强大工具集,成熟的生态 | 学习成本高,模板代码多 |
src/ ├── contexts/ │ ├── ThemeContext.js │ ├── AuthContext.js │ └── index.js ├── hooks/ │ └── useAuth.js └── components/