Zustand 是什么?相比 Redux 有什么优势?

Zustand 是一个轻量级 React 状态管理库,API 简洁,不需要 Provider 包裹。

基本用法

import { create } from 'zustand'

const useStore = create((set, get) => ({
  count: 0,
  name: 'Tom',
  
  increment: () => set(state => ({ count: state.count + 1 })),
  decrement: () => set(state => ({ count: state.count - 1 })),
  
  // 可以获取当前 state
  reset: () => set({ count: 0, name: 'Tom' }),
  
  // 异步操作不需要额外中间件
  fetchUser: async (id) => {
    const user = await api.getUser(id)
    set({ user })
  }
}))

// 组件中使用
function Counter() {
  const count = useStore(state => state.count)
  const increment = useStore(state => state.increment)
  
  return <button onClick={increment}>{count}</button>
}

// 也可以解构(不会重渲染问题)
const { count, increment } = useStore()

选择性订阅(性能优化)

// 只订阅 count,name 变化不触发重渲染
const count = useStore(state => state.count)

// 多个值
const { count, name } = useStore(state => ({
  count: state.count,
  name: state.name
}), shallow) // 需要 shallow 比较

// 使用 selector
const doubleCount = useStore(state => state.count * 2)

中间件

import { create } from 'zustand'
import { persist, devtools } from 'zustand/middleware'

const useStore = create(
  devtools(  // Redux DevTools 支持
    persist(  // localStorage 持久化
      (set) => ({
        theme: 'light',
        toggleTheme: () => set(state => ({
          theme: state.theme === 'light' ? 'dark' : 'light'
        }))
      }),
      { name: 'app-storage' }
    )
  )
)

跨组件共享

// 不需要 Provider,直接使用
// 任何组件都能访问
function Header() {
  const theme = useStore(state => state.theme)
  return <header className={theme}>...</header>
}

function Settings() {
  const toggleTheme = useStore(state => state.toggleTheme)
  return <button onClick={toggleTheme}>Toggle</button>
}

对比 Redux

特性 Redux Zustand
样板代码 多 极少
Provider 需要 不需要
不可变更新 必须 可选(可用 Immer)
异步 需要 thunk/saga 直接 async/await
包体积 ~2KB + RTK ~1KB
TypeScript 好(RTK) 优秀
学习成本 中 低

对比 Context

// Context:任何 context 值变化,所有消费者都重渲染
const AppContext = createContext()
// ❌ 大量组件订阅同一个 context 会有性能问题

// Zustand:精确订阅
const count = useStore(state => state.count) // 只有 count 变化才重渲染

什么时候用 Zustand

与其他轻量方案对比

同分类其他题目