useContext
面试速答(30 秒版 TL;DR)
useContext用来读取最近一层Context.Provider提供的值,解决的是跨层级传参问题。- 它适合放:主题、语言、登录态、表单上下文、组件库内部上下文。
- 它不是状态管理库的完全替代品,因为只解决“传递”问题,不自动解决复杂更新组织、派生、缓存和调试能力。
- React 18 下要特别注意:Provider value 变化会让消费它的组件重新渲染。
1. 心智模型
不用 Context 时,数据往往只能一层层透传:
- 父传子
- 子再传孙
这就是常说的 props drilling。
useContext 的作用不是让数据“变成全局”,而是提供一条跨层传递通道。
2. 基本用法
const ThemeContext = React.createContext<'light' | 'dark'>('light')
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
)
}
function Toolbar() {
const theme = useContext(ThemeContext)
return <div>{theme}</div>
}
核心规则:
- 就近读取最近的 Provider
- 找不到时返回
createContext(defaultValue)里的默认值
3. 它适合什么,不适合什么
3.1 适合
- 主题
theme - 国际化
locale - 认证信息
auth - 组件库内部上下文
- 表单或路由局部上下文
3.2 不适合直接承接所有复杂全局状态
因为一旦 Provider 的 value 变化,消费它的组件就可能重新渲染。
如果你把:
- 大对象
- 高频变化状态
- 很多无关字段
都塞进一个 Context,更新范围就容易变大。
4. React 18 下的性能关注点
4.1 value 引用稳定
下面这种写法每次 render 都会创建新对象:
<AuthContext.Provider value={{user, logout}}>
更稳的做法通常是结合 useMemo / useCallback 控制引用稳定。
4.2 拆 Context
不要把完全不同的关注点塞进一个 Context。
例如可以拆成:
AuthStateContextAuthActionContext
这样比一个大而全的对象更容易控制更新范围。
5. 面试高频答法
Q1:useContext 和 Redux / Zustand 有什么区别?
useContext主要解决跨层传值- Redux / Zustand 这类库还解决:
- 状态组织
- 派生与订阅
- 中间件
- DevTools
- 更新控制
所以 Context 更像“通道”,不是完整状态管理方案。
Q2:Context 会导致性能问题吗?
会,但不是“用了就慢”,而是:
- Provider value 改变
- 又没有合理拆分和稳定引用
这时消费组件更新范围可能被放大。
Q3:defaultValue 有什么用?
主要用于:
- 没有 Provider 时的兜底值
- 测试或演示场景的默认行为
但业务里一般仍建议明确包 Provider。
常见追问
1)可以在条件语句里调用 useContext 吗?
不可以。它仍然受 Hooks 调用顺序规则约束。
2)Context 是全局单例吗?
不是。它是按组件树作用域传播的。
易错点/坑
- 把 Context 当成“任何场景都适合的全局状态管理”。
- Provider
value每次都创建新对象,导致不必要更新。 - 一个 Context 塞太多字段,更新扩散过大。
速记要点(可背诵)
useContext解决的是跨层传值,不是完整状态管理。- React 18 下要关注 Provider
value的引用稳定和 Context 拆分。 - 适合主题、语言、认证、组件库内部上下文。