React 的 Context API 是用于跨组件层级传递数据的解决方案,尤其适合解决「prop drilling」(多层组件手动传递 props)的问题。以下是关于 Context 的详细解析:
React.createContext()
创建,包含 Provider
和 Consumer
两个组件。value
属性传递数据。useContext
Hook),通过订阅 Context 获取最新值。import React, { createContext, useContext, useState } from 'react';
// 1. 创建 Context(可选默认值)
const ThemeContext = createContext('light'); // 默认值 'light'
function App() {
const [theme, setTheme] = React.useState('dark');
return (
);
}
function ThemedButton() {
// 使用 useContext Hook 获取数据
const { theme, setTheme } = useContext(ThemeContext);
return (
);
}
在 React 函数式组件中使用 Context 主要通过 useContext
Hook 实现。以下是详细步骤和示例:
import React, { createContext, useContext, useState } from 'react';
// 1. 创建 Context(可选默认值)
const ThemeContext = createContext('light'); // 默认值 'light'
function App() {
const [theme, setTheme] = useState('dark');
return (
// Provider 通过 value 传递数据
);
}
function ThemedButton() {
// 使用 useContext Hook 获取数据
const { theme, setTheme } = useContext(ThemeContext);
return (
);
}
如果 Provider
的 value
是对象,每次父组件渲染会生成新对象,导致子组件无效重渲染。使用 useMemo
优化:
function App() {
const [theme, setTheme] = useState('dark');
// 使用 useMemo 避免重复创建对象
const value = useMemo(() => ({ theme, setTheme }), [theme]);
return (
);
}
将频繁更新的数据与不常更新的数据拆分到不同的 Context 中:
// UserContext(频繁更新)
const UserContext = createContext({ name: 'Guest' });
// ThemeContext(不常更新)
const ThemeContext = createContext('light');
通过 useState
或 useReducer
动态更新 Context:
function App() {
const [theme, setTheme] = useState('dark');
const toggleTheme = () => {
setTheme(prev => prev === 'dark' ? 'light' : 'dark');
};
return (
);
}
function ThemeSwitcher() {
const { toggleTheme } = useContext(ThemeContext);
return ;
}
const StateContext = createContext();
const DispatchContext = createContext();
function reducer(state, action) {
switch (action.type) {
case 'TOGGLE_THEME':
return { ...state, theme: state.theme === 'dark' ? 'light' : 'dark' };
default:
return state;
}
}
function App() {
const [state, dispatch] = useReducer(reducer, { theme: 'dark' });
return (
);
}
function ThemeSwitcher() {
const state = useContext(StateContext);
const dispatch = useContext(DispatchContext);
return (
);
}
操作 | 代码示例 | 适用场景 |
---|---|---|
创建 Context | createContext(defaultValue) |
定义全局状态 |
提供数据 |
|
父组件向任意深度子组件传值 |
消费数据 | useContext(ThemeContext) |
函数组件中直接获取数据 |
动态更新 | value={{ theme, setTheme }} |
需要响应式更新的场景 |
性能优化 | useMemo 优化 Provider 的 value |
避免无效重渲染 |
// ThemeContext.js
import React, { createContext, useContext, useState } from 'react';
// 创建主题上下文,默认值为 'light'
const ThemeContext = createContext();
/**
* 主题提供者组件
* @param {Object} props - 组件属性
* @param {React.ReactNode} props.children - 子组件
*/
export function ThemeProvider({ children }) {
// 使用 useState 管理主题状态,初始值为 'light'
const [theme, setTheme] = useState('light');
// 切换主题的函数
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
// 通过 Provider 向下传递主题状态和切换函数
{/* 根容器动态添加主题类名 */}
{children}
);
}
/**
* 自定义主题 Hook
* @returns {{theme: string, toggleTheme: function}} 主题对象
*/
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme 必须在 ThemeProvider 内使用');
}
return context;
};
// App.js
import { ThemeProvider } from './ThemeContext';
function App() {
return (
// 包裹应用根组件提供主题功能
);
}
// Header.js
import { useTheme } from './ThemeContext';
function Header() {
// 获取当前主题状态和切换函数
const { theme, toggleTheme } = useTheme();
return (
My App
{/* 主题切换按钮 */}
);
}
// AuthContext.js
import React, { createContext, useContext, useState } from 'react';
// 创建认证上下文
const AuthContext = createContext();
/**
* 认证提供者组件
* @param {Object} props - 组件属性
* @param {React.ReactNode} props.children - 子组件
*/
export function AuthProvider({ children }) {
// 用户信息状态
const [user, setUser] = useState(null);
// 认证状态
const [isAuthenticated, setIsAuthenticated] = useState(false);
// 登录方法
const login = (userData) => {
setUser(userData);
setIsAuthenticated(true);
};
// 退出方法
const logout = () => {
setUser(null);
setIsAuthenticated(false);
};
return (
{children}
);
}
/**
* 自定义认证 Hook
* @returns {{
* user: Object|null,
* isAuthenticated: boolean,
* login: function,
* logout: function
* }} 认证上下文对象
*/
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth 必须在 AuthProvider 内使用');
}
return context;
};
// ProtectedRoute.js
import { useAuth } from './AuthContext';
import { Navigate } from 'react-router-dom';
/**
* 保护路由组件
* @param {Object} props - 组件属性
* @param {React.ReactNode} props.children - 子路由
*/
function ProtectedRoute({ children }) {
const { isAuthenticated } = useAuth();
// 未认证时跳转到登录页
if (!isAuthenticated) {
return ;
}
return children;
}
// UserProfile.js
import { useAuth } from './AuthContext';
function UserProfile() {
const { user, logout } = useAuth();
return (
用户资料
{user ? (
<>
姓名:{user.name}
邮箱:{user.email}
角色:{user.role}
>
) : (
⚠️ 未获取到用户信息
)}
);
}
// I18nContext.js
import React, { createContext, useContext, useState } from 'react';
// 翻译字典配置
const translations = {
en: {
greeting: 'Hello',
button: 'Click me',
welcome: 'Welcome to our app'
},
zh: {
greeting: '你好',
button: '点击我',
welcome: '欢迎使用我们的应用'
}
};
// 创建国际化上下文
const I18nContext = createContext();
/**
* 国际化提供者组件
* @param {Object} props - 组件属性
* @param {React.ReactNode} props.children - 子组件
*/
export function I18nProvider({ children }) {
// 当前语言状态,默认英文
const [locale, setLocale] = useState('en');
/**
* 翻译函数
* @param {string} key - 翻译键
* @returns {string} 翻译文本
*/
const t = (key) => translations[locale][key] || key;
return (
{children}
);
}
/**
* 自定义国际化 Hook
* @returns {{
* locale: string,
* setLocale: function,
* t: function
* }} 国际化上下文对象
*/
export const useI18n = () => {
const context = useContext(I18nContext);
if (!context) {
throw new Error('useI18n 必须在 I18nProvider 内使用');
}
return context;
};
// LanguageSwitcher.js
import { useI18n } from './I18nContext';
function LanguageSwitcher() {
const { locale, setLocale } = useI18n();
return (
);
}
// Greeting.js
import { useI18n } from './I18nContext';
function Greeting() {
const { t } = useI18n();
return (
{t('welcome')}
);
}
// CartContext.js
import React, { createContext, useContext, useReducer } from 'react';
// 创建购物车上下文
const CartContext = createContext();
/**
* 购物车 reducer 处理函数
* @param {Object} state - 当前状态
* @param {Object} action - 操作对象
*/
const cartReducer = (state, action) => {
switch (action.type) {
case 'ADD_ITEM':
// 检查是否已存在相同商品
const existingItem = state.items.find(
item => item.id === action.payload.id
);
if (existingItem) {
// 数量增加
return {
...state,
items: state.items.map(item =>
item.id === action.payload.id
? { ...item, quantity: item.quantity + 1 }
: item
)
};
}
// 新增商品
return {
...state,
items: [...state.items, { ...action.payload, quantity: 1 }]
};
case 'REMOVE_ITEM':
// 过滤移除商品
return {
...state,
items: state.items.filter(
item => item.id !== action.payload.id
)
};
case 'CLEAR_CART':
// 清空购物车
return { ...state, items: [] };
default:
return state;
}
};
/**
* 购物车提供者组件
* @param {Object} props - 组件属性
* @param {React.ReactNode} props.children - 子组件
*/
export function CartProvider({ children }) {
// 使用 useReducer 管理复杂状态
const [cart, dispatch] = useReducer(cartReducer, { items: [] });
// 添加商品到购物车
const addToCart = (product) => {
dispatch({ type: 'ADD_ITEM', payload: product });
};
// 从购物车移除商品
const removeFromCart = (productId) => {
dispatch({ type: 'REMOVE_ITEM', payload: { id: productId } });
};
// 清空购物车
const clearCart = () => {
dispatch({ type: 'CLEAR_CART' });
};
// 计算总数量
const totalItems = cart.items.reduce(
(sum, item) => sum + item.quantity, 0
);
// 计算总金额
const totalPrice = cart.items.reduce(
(sum, item) => sum + (item.price * item.quantity), 0
);
return (
{children}
);
}
/**
* 自定义购物车 Hook
* @returns {{
* cart: Object,
* addToCart: function,
* removeFromCart: function,
* clearCart: function,
* totalItems: number,
* totalPrice: number
* }} 购物车上下文对象
*/
export const useCart = () => {
const context = useContext(CartContext);
if (!context) {
throw new Error('useCart 必须在 CartProvider 内使用');
}
return context;
};
// ProductItem.js
import { useCart } from './CartContext';
function ProductItem({ product }) {
const { addToCart } = useCart();
return (
{product.name}
价格:${product.price}
);
}
// CartSummary.js
import { useCart } from './CartContext';
function CartSummary() {
const {
cart,
removeFromCart,
clearCart,
totalItems,
totalPrice
} = useCart();
return (
️ 购物车({totalItems} 件商品)
{cart.items.map(item => (
-
{item.name} × {item.quantity}
${item.price * item.quantity}
))}
总计:${totalPrice}
);
}
// FormContext.js
import React, { createContext, useContext, useState } from 'react';
// 创建表单上下文
const FormContext = createContext();
/**
* 表单提供者组件
* @param {Object} props - 组件属性
* @param {React.ReactNode} props.children - 子组件
*/
export function FormProvider({ children }) {
// 管理复杂表单数据结构
const [formData, setFormData] = useState({
personalInfo: {
firstName: '',
lastName: '',
email: ''
},
address: {
street: '',
city: '',
zipCode: ''
},
preferences: {
newsletter: false,
notifications: true
}
});
/**
* 更新表单字段
* @param {string} section - 表单区块(personalInfo/address/preferences)
* @param {string} field - 字段名称
* @param {any} value - 字段值
*/
const updateField = (section, field, value) => {
setFormData(prev => ({
...prev,
[section]: {
...prev[section],
[field]: value
}
}));
};
// 表单验证方法
const validateForm = () => {
// 示例验证逻辑
const isValid = !!(
formData.personalInfo.firstName &&
formData.personalInfo.email.includes('@')
);
return isValid;
};
return (
{children}
);
}
/**
* 自定义表单 Hook
* @returns {{
* formData: Object,
* updateField: function,
* validateForm: function
* }} 表单上下文对象
*/
export const useForm = () => {
const context = useContext(FormContext);
if (!context) {
throw new Error('useForm 必须在 FormProvider 内使用');
}
return context;
};
// PersonalInfoStep.js
import { useForm } from './FormContext';
function PersonalInfoStep() {
const { formData, updateField } = useForm();
return (
个人信息
updateField('personalInfo', 'firstName', e.target.value)
}
placeholder="请输入名字"
/>
updateField('personalInfo', 'lastName', e.target.value)
}
placeholder="请输入姓氏"
/>
updateField('personalInfo', 'email', e.target.value)
}
placeholder="[email protected]"
/>
);
}
// FormSubmit.js
import { useForm } from './FormContext';
function FormSubmit() {
const { formData, validateForm } = useForm();
const handleSubmit = () => {
if (validateForm()) {
console.log('✅ 表单验证通过,提交数据:', formData);
// 这里可以添加实际的提交逻辑
alert('表单提交成功!');
} else {
console.log('❌ 表单验证失败');
alert('请填写必填字段!');
}
};
return (
);
}