Skip to content

比较

比较

Zustand如何与类似的库相比较?

Zustand是React的众多状态管理库之一。在这个页面上,我们将讨论Zustand与其中一些库,包括Redux、Valtio、Jotai和Recoil的比较。

每个库都有其自身的优点和缺点,我们将比较每个库之间的关键差异和相似之处。

Redux

状态模型 (vs Redux)

从概念上讲,Zustand 和 Redux 非常相似,它们都基于不可变状态模型。然而,Redux 需要将应用程序包裹在上下文提供者中;Zustand 则不需要。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
increment: (qty: number) => void
decrement: (qty: number) => void
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
increment: (qty: number) => set((state) => ({ count: state.count + qty })),
decrement: (qty: number) => set((state) => ({ count: state.count - qty })),
}))
import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
increment: (qty: number) => void
decrement: (qty: number) => void
}
type Action = {
type: keyof Actions
qty: number
}
const countReducer = (state: State, action: Action) => {
switch (action.type) {
case 'increment':
return { count: state.count + action.qty }
case 'decrement':
return { count: state.count - action.qty }
default:
return state
}
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
dispatch: (action: Action) => set((state) => countReducer(state, action)),
}))

Redux

import { createStore } from 'redux'
import { useSelector, useDispatch } from 'react-redux'
type State = {
count: number
}
type Action = {
type: 'increment' | 'decrement'
qty: number
}
const countReducer = (state: State, action: Action) => {
switch (action.type) {
case 'increment':
return { count: state.count + action.qty }
case 'decrement':
return { count: state.count - action.qty }
default:
return state
}
}
const countStore = createStore(countReducer)
import { createSlice, configureStore } from '@reduxjs/toolkit'
const countSlice = createSlice({
name: 'count',
initialState: { value: 0 },
reducers: {
incremented: (state, qty: number) => {
// Redux Toolkit does not mutate the state, it uses the Immer library
// behind scenes, allowing us to have something called "draft state".
state.value += qty
},
decremented: (state, qty: number) => {
state.value -= qty
},
},
})
const countStore = configureStore({ reducer: countSlice.reducer })

渲染优化(对比 Redux)

在应用程序的渲染优化方面,Zustand 和 Redux 之间的处理方法没有太大区别。在这两个库中,都建议通过使用选择器手动应用渲染优化。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
increment: (qty: number) => void
decrement: (qty: number) => void
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
increment: (qty: number) => set((state) => ({ count: state.count + qty })),
decrement: (qty: number) => set((state) => ({ count: state.count - qty })),
}))
const Component = () => {
const count = useCountStore((state) => state.count)
const increment = useCountStore((state) => state.increment)
const decrement = useCountStore((state) => state.decrement)
// ...
}

Redux

import { createStore } from 'redux'
import { useSelector, useDispatch } from 'react-redux'
type State = {
count: number
}
type Action = {
type: 'increment' | 'decrement'
qty: number
}
const countReducer = (state: State, action: Action) => {
switch (action.type) {
case 'increment':
return { count: state.count + action.qty }
case 'decrement':
return { count: state.count - action.qty }
default:
return state
}
}
const countStore = createStore(countReducer)
const Component = () => {
const count = useSelector((state) => state.count)
const dispatch = useDispatch()
// ...
}
import { useSelector } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import { createSlice, configureStore } from '@reduxjs/toolkit'
const countSlice = createSlice({
name: 'count',
initialState: { value: 0 },
reducers: {
incremented: (state, qty: number) => {
// Redux Toolkit does not mutate the state, it uses the Immer library
// behind scenes, allowing us to have something called "draft state".
state.value += qty
},
decremented: (state, qty: number) => {
state.value -= qty
},
},
})
const countStore = configureStore({ reducer: countSlice.reducer })
const useAppSelector: TypedUseSelectorHook<typeof countStore.getState> =
useSelector
const useAppDispatch: () => typeof countStore.dispatch = useDispatch
const Component = () => {
const count = useAppSelector((state) => state.count.value)
const dispatch = useAppDispatch()
// ...
}

Valtio

状态模型 (vs Valtio)

Zustand 和 Valtio 在状态管理上采用了根本不同的方法。Zustand 基于不可变状态模型,而 Valtio 基于可变状态模型。

Zustand

import { create } from 'zustand'
type State = {
obj: { count: number }
}
const store = create<State>(() => ({ obj: { count: 0 } }))
store.setState((prev) => ({ obj: { count: prev.obj.count + 1 } }))

Valtio

import { proxy } from 'valtio'
const state = proxy({ obj: { count: 0 } })
state.obj.count += 1

渲染优化(对比 Valtio)

Zustand 和 Valtio 之间的另一个区别是,Valtio 通过属性访问进行渲染优化。然而,对于 Zustand,建议通过使用选择器手动应用渲染优化。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
const useCountStore = create<State>(() => ({
count: 0,
}))
const Component = () => {
const count = useCountStore((state) => state.count)
// ...
}

Valtio

import { proxy, useSnapshot } from 'valtio'
const state = proxy({
count: 0,
})
const Component = () => {
const { count } = useSnapshot(state)
// ...
}

Jotai

状态模型 (vs Jotai)

Zustand 和 Jotai 之间有两个主要区别。首先,Zustand 是一个单一的存储,而 Jotai 由可以组合在一起的原子组成。其次,Zustand 存储是一个外部存储,这使得它在需要在 React 之外进行访问时更为适用。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
updateCount: (
countCallback: (count: State['count']) => State['count'],
) => void
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
updateCount: (countCallback) =>
set((state) => ({ count: countCallback(state.count) })),
}))

Jotai

import { atom } from 'jotai'
const countAtom = atom<number>(0)

渲染优化(对比 Jotai)

Jotai 通过原子依赖实现渲染优化。然而,对于 Zustand,建议通过使用选择器手动应用渲染优化。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
updateCount: (
countCallback: (count: State['count']) => State['count'],
) => void
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
updateCount: (countCallback) =>
set((state) => ({ count: countCallback(state.count) })),
}))
const Component = () => {
const count = useCountStore((state) => state.count)
const updateCount = useCountStore((state) => state.updateCount)
// ...
}

Jotai

import { atom, useAtom } from 'jotai'
const countAtom = atom<number>(0)
const Component = () => {
const [count, updateCount] = useAtom(countAtom)
// ...
}

Recoil

状态模型 (vs Recoil)

Zustand 和 Recoil 之间的区别类似于 Zustand 和 Jotai 之间的区别。Recoil 依赖于原子字符串键,而不是原子对象引用标识。此外,Recoil 需要将应用程序包裹在上下文提供者中。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
setCount: (countCallback: (count: State['count']) => State['count']) => void
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
setCount: (countCallback) =>
set((state) => ({ count: countCallback(state.count) })),
}))

Recoil

import { atom } from 'recoil'
const count = atom({
key: 'count',
default: 0,
})

渲染优化(对比 Recoil)

与之前的优化比较类似,Recoil 通过原子依赖实现渲染优化。而在 Zustand 中,建议您通过使用选择器手动应用渲染优化。

Zustand

import { create } from 'zustand'
type State = {
count: number
}
type Actions = {
setCount: (countCallback: (count: State['count']) => State['count']) => void
}
const useCountStore = create<State & Actions>((set) => ({
count: 0,
setCount: (countCallback) =>
set((state) => ({ count: countCallback(state.count) })),
}))
const Component = () => {
const count = useCountStore((state) => state.count)
const setCount = useCountStore((state) => state.setCount)
// ...
}

Recoil

import { atom, useRecoilState } from 'recoil'
const countAtom = atom({
key: 'count',
default: 0,
})
const Component = () => {
const [count, setCount] = useRecoilState(countAtom)
// ...
}

Npm 下载趋势

React状态管理库的Npm下载趋势