useContext 与跨组件通信
约 344 字大约 1 分钟
布欧-Lewyon
2026-05-15
Context 创建
import { createContext, useContext, useState } from 'react'
// 1. 创建 Context
interface ThemeContextType {
theme: 'light' | 'dark'
toggleTheme: () => void
}
const ThemeContext = createContext<ThemeContextType | null>(null)
// 2. Provider 提供值
function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light')
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light')
}
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
)
}
// 3. 消费
function ThemeButton() {
const context = useContext(ThemeContext)
if (!context) throw new Error('useTheme must be within ThemeProvider')
return (
<button
onClick={context.toggleTheme}
style={{
background: context.theme === 'light' ? '#fff' : '#333',
color: context.theme === 'light' ? '#000' : '#fff'
}}
>
Toggle Theme
</button>
)
}
// 使用
function App() {
return (
<ThemeProvider>
<ThemeButton />
</ThemeProvider>
)
}自定义 Hook 封装
function useTheme() {
const context = useContext(ThemeContext)
if (!context) throw new Error('useTheme must be used within ThemeProvider')
return context
}
// 使用
function Navbar() {
const { theme, toggleTheme } = useTheme()
// ...
}Context vs Props
| 对比 | Props | Context |
|---|---|---|
| 传递深度 | 需要逐层传递 | 任意层级直接读取 |
| 组件复用 | ✅ 更好 | ⚠️ 依赖 Context 降低复用 |
| 调试 | 容易 | 较难 |
| 性能 | 不需要优化 | Consumer 重渲染范围广 |
选择标准:如果 Props 传递超过 3 层 → 考虑 Context。
小结
createContext+Provider+useContext实现跨组件数据传递。- 自定义 Hook 封装 useContext,提供类型安全和默认值处理。
- Context 适合主题/用户/语言等全局数据,避免 Props 层层传递。
- 频繁更新的数据不适合用 Context(引起大量子组件重渲染)。
上一节:useRef 与 DOM 下一节:useReducer 与复杂状态
