目录
[一、Context 的核心概念](#一、Context 的核心概念)
[1. 什么是 Context?](#1. 什么是 Context?)
[2. 核心三要素:](#2. 核心三要素:)
[适合场景 ✅](#适合场景 ✅)
[不适合场景 ❌](#不适合场景 ❌)
[1. 创建 Context](#1. 创建 Context)
[2. 提供 Context](#2. 提供 Context)
[3. 消费 Context](#3. 消费 Context)
[1.Context.Consumer 使用详解](#1.Context.Consumer 使用详解)
[1. 基础用法(类组件)](#1. 基础用法(类组件))
[2. 嵌套 Consumer(多 Context)](#2. 嵌套 Consumer(多 Context))
[2、useContext 使用详解](#2、useContext 使用详解)
[1. 基础用法(函数组件)](#1. 基础用法(函数组件))
[2. 复杂对象消费](#2. 复杂对象消费)
[1. 自定义 Hook 封装](#1. 自定义 Hook 封装)
[2. 类组件中使用 Context(两种方式)](#2. 类组件中使用 Context(两种方式))
[1. 未提供 Provider](#1. 未提供 Provider)
[2. 直接传递对象导致重复渲染](#2. 直接传递对象导致重复渲染)
[1. 默认值不生效?](#1. 默认值不生效?)
[2. 组件不更新?](#2. 组件不更新?)
[3. 多个 Context 如何管理?](#3. 多个 Context 如何管理?)
[4. Class 组件如何使用?](#4. Class 组件如何使用?)
[七、Context vs Redux](#七、Context vs Redux)
一、Context 的核心概念
1. 什么是 Context?
-
React 官方提供的跨层级组件通信方案
-
解决 props drilling(深层级 props 传递)问题
-
适合全局共享数据(如主题、用户身份、语言等)
2. 核心三要素:
-
React.createContext()
创建 Context 对象,可指定默认值
TypeScriptconst ThemeContext = React.createContext('light');
-
Context.Provider
数据提供者组件,通过
value
属性传递数据TypeScript<ThemeContext.Provider value="dark"> <App /> </ThemeContext.Provider>
-
Context.Consumer
或useContext
数据消费者,用于获取上下文值
TypeScript// 类组件 <ThemeContext.Consumer> {value => <div>{value}</div>} </ThemeContext.Consumer> // 函数组件 const theme = useContext(ThemeContext);
二、使用场景分析
适合场景 ✅
-
全局主题切换
-
用户认证信息共享
-
多语言国际化
-
全局配置参数
-
跨 3+ 层组件的数据传递
不适合场景 ❌
-
高频更新数据(优先考虑状态管理库如 Redux)
-
简单父子组件通信(直接用 props)
-
组件内部私有状态(使用 useState)
三、完整使用示例
1. 创建 Context
TypeScript
// ThemeContext.js
import { createContext } from 'react';
const ThemeContext = createContext({
theme: 'light',
toggleTheme: () => {},
});
export default ThemeContext;
2. 提供 Context
TypeScript
// App.jsx
import { useState } from 'react';
import ThemeContext from './ThemeContext';
import Toolbar from './Toolbar';
export default function App() {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => (prev === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<Toolbar />
</ThemeContext.Provider>
);
}
3. 消费 Context
TypeScript
// Toolbar.jsx
import { useContext } from 'react';
import ThemeContext from './ThemeContext';
export default function Toolbar() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === 'dark' ? '#333' : '#fff' }}>
<button onClick={toggleTheme}>
Toggle Theme ({theme})
</button>
</div>
);
}
四、context使用详解
1.Context.Consumer 使用详解
1. 基础用法(类组件)
TypeScript
import React from 'react';
// 创建 Context
const ThemeContext = React.createContext('light');
// 类组件中使用 Consumer
class ThemedButton extends React.Component {
render() {
return (
<ThemeContext.Consumer>
{(theme) => (
<button style={{
background: theme === 'dark' ? '#333' : '#fff',
color: theme === 'dark' ? '#fff' : '#333'
}}>
{this.props.children}
</button>
)}
</ThemeContext.Consumer>
);
}
}
// Provider 设置
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton>Click me</ThemedButton>
</ThemeContext.Provider>
);
}
2. 嵌套 Consumer(多 Context)
TypeScript
const ThemeContext = React.createContext('light');
const UserContext = React.createContext('Guest');
function Toolbar() {
return (
<ThemeContext.Consumer>
{(theme) => (
<UserContext.Consumer>
{(user) => (
<div style={{
background: theme,
padding: '10px'
}}>
Logged in as: {user}
</div>
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
// Provider 嵌套
function App() {
return (
<ThemeContext.Provider value="dark">
<UserContext.Provider value="Alice">
<Toolbar />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
2、useContext 使用详解
1. 基础用法(函数组件)
TypeScript
import React, { useContext } from 'react';
const ThemeContext = React.createContext('light');
function ThemedButton() {
// 使用 useContext 获取值
const theme = useContext(ThemeContext);
return (
<button style={{
background: theme === 'dark' ? '#333' : '#fff',
color: theme === 'dark' ? '#fff' : '#333'
}}>
Click me
</button>
);
}
// 动态更新示例
function App() {
const [theme, setTheme] = React.useState('light');
return (
<ThemeContext.Provider value={theme}>
<ThemedButton />
<button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</ThemeContext.Provider>
);
}
2. 复杂对象消费
TypeScript
const UserContext = React.createContext({
name: 'Guest',
role: 'user',
login: () => {}
});
function UserPanel() {
// 解构获取多个值
const { name, role, login } = useContext(UserContext);
return (
<div>
<p>Name: {name}</p>
<p>Role: {role}</p>
<button onClick={login}>Login</button>
</div>
);
}
function App() {
const [user, setUser] = React.useState({
name: 'Alice',
role: 'admin'
});
const loginHandler = () => {
setUser({ name: 'Bob', role: 'editor' });
};
return (
<UserContext.Provider value={{
...user,
login: loginHandler
}}>
<UserPanel />
</UserContext.Provider>
);
}
3、对比总结
特性 | Context.Consumer |
useContext |
---|---|---|
组件类型 | 适用于类组件 | 仅适用于函数组件 |
代码简洁性 | 需要嵌套函数 | 直接返回值,代码更简洁 |
多 Context 使用 | 需要多层嵌套 Consumer | 可多次调用 useContext |
动态更新 | 自动响应 Provider 更新 | 自动响应 Provider 更新 |
性能优化 | 需注意避免不必要的渲染 | 结合 memo 使用更易优化 |
4、高级模式示例
1. 自定义 Hook 封装
TypeScript
// 创建自定义 Hook
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
// 使用自定义 Hook
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
Current Theme: {theme}
</button>
);
}
2. 类组件中使用 Context(两种方式)
TypeScript
// 方式一:static contextType
class ThemeDisplay extends React.Component {
static contextType = ThemeContext;
render() {
return <div>Current Theme: {this.context}</div>;
}
}
// 方式二:Consumer
class ThemeButton extends React.Component {
render() {
return (
<ThemeContext.Consumer>
{(theme) => (
<button style={{ background: theme }}>
{this.props.children}
</button>
)}
</ThemeContext.Consumer>
);
}
}
5、常见错误示例
1. 未提供 Provider
TypeScript
// 错误:使用默认值但期望动态更新
function BrokenComponent() {
const theme = useContext(ThemeContext); // 默认值 'light'
return <div>{theme}</div>; // 永远显示 'light'
}
// 正确做法:确保外层有 Provider
function App() {
return (
<ThemeContext.Provider value="dark">
<BrokenComponent />
</ThemeContext.Provider>
);
}
2. 直接传递对象导致重复渲染
TypeScript
// 错误写法:每次渲染创建新对象
function App() {
return (
<ThemeContext.Provider value={{ theme: 'dark' }}> {/* 每次渲染新对象 */}
<Child />
</ThemeContext.Provider>
);
}
// 正确做法:使用 useMemo
function App() {
const value = useMemo(() => ({ theme: 'dark' }), []);
return (
<ThemeContext.Provider value={value}>
<Child />
</ThemeContext.Provider>
);
}
通过这些示例,可以更清晰地理解 Context.Consumer
和 useContext
的具体用法与差异。实际开发中:
-
优先使用
useContext
(函数组件) -
类组件使用
static contextType
或Consumer
-
复杂场景结合
useMemo
+memo
优化性能
五、性能优化策略
-
拆分 Context
将高频更新和低频更新的数据分离到不同 Context
TypeScript// 分开定义 const SettingsContext = createContext(); const UserContext = createContext();
-
记忆化值对象
使用
useMemo
避免不必要的重渲染TypeScriptconst contextValue = useMemo(() => ({ theme, toggleTheme }), [theme]);
-
使用选择器模式
通过高阶组件实现精准订阅(类似 Redux 的 connect)
TypeScriptconst useTheme = () => { const { theme } = useContext(ThemeContext); return theme; };
-
避免嵌套 Provider
保持 Provider 层级扁平化
六、常见问题解决方案
1. 默认值不生效?
-
确保组件树中没有匹配的 Provider 时才会使用默认值
-
总是显式提供 Provider 的
value
属性
2. 组件不更新?
-
检查 Provider 的
value
是否总是创建新对象 -
使用
useMemo
优化:TypeScriptconst value = useMemo(() => ({ theme, toggleTheme }), [theme]);
3. 多个 Context 如何管理?
-
使用组合 Provider:
TypeScript<UserProvider> <ThemeProvider> <App /> </ThemeProvider> </UserProvider>
4. Class 组件如何使用?
-
使用
static contextType
或Context.Consumer
TypeScriptclass MyClass extends React.Component { static contextType = ThemeContext; render() { const { theme } = this.context; return <div>{theme}</div>; } }
七、Context vs Redux
特性 | Context API | Redux |
---|---|---|
学习成本 | 低 | 较高 |
调试工具 | 无内置 | Redux DevTools |
中间件支持 | 不支持 | 支持 |
适用场景 | 中小应用 | 大型复杂应用 |
性能优化 | 需手动优化 | 自动优化 |
代码量 | 较少 | 较多 |
八、最佳实践
-
避免滥用:只在需要跨多层组件通信时使用
-
类型安全:配合 TypeScript 定义 context 类型
TypeScriptinterface ThemeContextType { theme: 'light' | 'dark'; toggleTheme: () => void; }
-
文档规范:为每个 Context 添加使用说明
-
测试策略:使用 Mock Provider 进行单元测试
码字不易,各位大佬点点赞呗