React Context 的原理和性能问题是什么?如何优化?

Context 基本用法

const ThemeContext = createContext('light')

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Child />
    </ThemeContext.Provider>
  )
}

function Child() {
  const theme = useContext(ThemeContext)
  return <div>{theme}</div> // 'dark'
}

原理

  1. Provider 的 value 变化时,React 会重新渲染所有消费该 Context 的组件
  2. 即使子组件被 React.memo 包裹,Context 变化也会跳过 memo 直接渲染

性能问题

问题:Provider value 每次渲染都是新对象,导致所有消费者重渲染

// ❌ 每次渲染都创建新对象
function App() {
  const [count, setCount] = useState(0)
  
  return (
    <UserContext.Provider value={{ user, logout }}>
      {/* count 变化时,即使用户信息没变,消费 UserContext 的组件也会重渲染 */}
      <ExpensiveTree />
    </UserContext.Provider>
  )
}

优化方案

1. useMemo 缓存 value

function App() {
  const [count, setCount] = useState(0)
  const [user, setUser] = useState(null)

  const value = useMemo(() => ({ user, logout }), [user])

  return (
    <UserContext.Provider value={value}>
      <ExpensiveTree />
    </UserContext.Provider>
  )
}

2. 拆分 Context

// 将频繁变化的和不变的分开
const UserContext = createContext()      // 不常变化
const ThemeContext = createContext()     // 偶尔变化
const CartContext = createContext()      // 频繁变化

// 各自独立 Provider
<UserContext.Provider value={userValue}>
  <ThemeContext.Provider value={themeValue}>
    <CartContext.Provider value={cartValue}>
      <App />
    </CartContext.Provider>
  </ThemeContext.Provider>
</UserContext.Provider>

3. use-context-selector(第三方库)

import { createContext, useContextSelector } from 'use-context-selector'

const UserContext = createContext()

function Name() {
  // 只订阅 user.name,其他属性变化不触发
  const name = useContextSelector(UserContext, state => state.name)
  return <div>{name}</div>
}

4. 状态下放

// ❌ count 在 Provider 外面,变化不影响 Provider
function App() {
  return (
    <UserContext.Provider value={value}>
      <Counter /> {/* count 变化不影响其他消费者 */}
    </UserContext.Provider>
  )
}

const Counter = React.memo(() => {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>
})

什么时候用 Context

替代方案对比

方案 适合场景 性能
Context 低频全局状态 中(需优化)
Zustand 通用全局状态 好
Jotai 细粒度原子状态 优秀
Redux 大型复杂应用 好

同分类其他题目