主题
比较
¥Comparison
Zustand 是 React 的众多状态管理库之一。在此页面上,我们将讨论 Zustand 与其中一些库的比较,包括 Redux、Valtio、Jotai 和 Recoil。
¥Zustand is one of many state management libraries for React. On this page we will discuss Zustand in comparison to some of these libraries, including Redux, Valtio, Jotai, and Recoil.
每个库都有自己的优点和缺点,我们将比较每个库之间的主要差异和相似之处。
¥Each library has its own strengths and weaknesses, and we will compare key differences and similarities between each.
Redux
状态模型 (vs Redux)
¥State Model (vs Redux)
从概念上讲,Zustand 和 Redux 非常相似,都基于不可变状态模型。但是,Redux 要求你的应用封装在上下文提供程序中;状态不重要。
¥Conceptually, Zustand and Redux are quite similar, both are based on an immutable state model. However, Redux requires your app to be wrapped in context providers; Zustand does not.
状态
¥Zustand
ts
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 })),
}))
ts
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
ts
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)
ts
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 相比)
¥Render Optimization (vs Redux)
在应用内的渲染优化方面,Zustand 和 Redux 之间的方法没有太大区别。在这两个库中,建议你使用选择器手动应用渲染优化。
¥When it comes to render optimizations within your app, there are no major differences in approach between Zustand and Redux. In both libraries it is recommended that you manually apply render optimizations by using selectors.
状态
¥Zustand
ts
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
ts
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()
// ...
}
ts
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)
¥State Model (vs Valtio)
Zustand 和 Valtio 以根本不同的方式处理状态管理。Zustand 基于不可变状态模型,而 Valtio 基于可变状态模型。
¥Zustand and Valtio approach state management in a fundamentally different way. Zustand is based on the immutable state model, while Valtio is based on the mutable state model.
状态
¥Zustand
ts
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
ts
import { proxy } from 'valtio'
const state = proxy({ obj: { count: 0 } })
state.obj.count += 1
渲染优化(与 Valtio)
¥Render Optimization (vs Valtio)
Zustand 和 Valtio 之间的另一个区别是 Valtio 通过属性访问进行渲染优化。但是,使用 Zustand 时,建议你使用选择器手动应用渲染优化。
¥The other difference between Zustand and Valtio is Valtio makes render optimizations through property access. However, with Zustand, it is recommended that you manually apply render optimizations by using selectors.
状态
¥Zustand
ts
import { create } from 'zustand'
type State = {
count: number
}
const useCountStore = create<State>(() => ({
count: 0,
}))
const Component = () => {
const count = useCountStore((state) => state.count)
// ...
}
Valtio
ts
import { proxy, useSnapshot } from 'valtio'
const state = proxy({
count: 0,
})
const Component = () => {
const { count } = useSnapshot(state)
// ...
}
Jotai
状态模型 (vs Jotai)
¥State Model (vs Jotai)
Zustand 和 Jotai 之间有一个主要区别。Zustand 是一个单一存储,而 Jotai 由可以组合在一起的原始原子组成。
¥There is one major difference between Zustand and Jotai. Zustand is a single store, while Jotai consists of primitive atoms that can be composed together.
状态
¥Zustand
ts
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
ts
import { atom } from 'jotai'
const countAtom = atom<number>(0)
渲染优化(与 Jotai 相比)
¥Render Optimization (vs Jotai)
Jotai 通过原子依赖实现渲染优化。但是,使用 Zustand 时,建议你使用选择器手动应用渲染优化。
¥Jotai achieves render optimizations through atom dependency. However, with Zustand it is recommended that you manually apply render optimizations by using selectors.
状态
¥Zustand
ts
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
ts
import { atom, useAtom } from 'jotai'
const countAtom = atom<number>(0)
const Component = () => {
const [count, updateCount] = useAtom(countAtom)
// ...
}
Recoil
状态模型 (vs Recoil)
¥State Model (vs Recoil)
Zustand 和 Recoil 之间的区别与 Zustand 和 Jotai 之间的区别类似。Recoil 依赖于原子字符串键而不是原子对象引用标识。此外,Recoil 需要将你的应用封装在上下文提供程序中。
¥The difference between Zustand and Recoil is similar to that between Zustand and Jotai. Recoil depends on atom string keys instead of atom object referential identities. Additionally, Recoil needs to wrap your app in a context provider.
状态
¥Zustand
ts
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
ts
import { atom } from 'recoil'
const count = atom({
key: 'count',
default: 0,
})
渲染优化(与 Recoil 相比)
¥Render Optimization (vs Recoil)
与之前的优化比较类似,Recoil 通过原子依赖进行渲染优化。而对于 Zustand,建议你使用选择器手动应用渲染优化。
¥Similar to previous optimization comparisons, Recoil makes render optimizations through atom dependency. Whereas with Zustand, it is recommended that you manually apply render optimizations by using selectors.
状态
¥Zustand
ts
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
ts
import { atom, useRecoilState } from 'recoil'
const countAtom = atom({
key: 'count',
default: 0,
})
const Component = () => {
const [count, setCount] = useRecoilState(countAtom)
// ...
}
Npm 下载趋势
¥Npm Downloads Trend