什么是 Zustand?React 前端状态管理

zustand
Zustand

 

Zustand 吉祥物

序言

为什么要分享这项技术?

与 Redux 相比,Zustatnd 本身是一种相对较新的技术,它也是我的团队正在尝试实施的一种前端状态管理技术。通过实际实施,我有了一些经验和想法,然后就有了写这篇文章的想法。

现有架构遇到了什么问题?

无论是使用 Redux 还是 Context 来处理状态管理,Zustand 都比 Zustand 复杂,对于后来加入项目的工程师来说,需要花时间去理解它。Zustand 的主要目标是让前端状态管理变得相对简单易懂,这一特性让 Zustand 成为一些公司的选择。


关于状态管理

在介绍 Zustand 之前,先来了解一下什么是 "状态管理"?

目前,网页变得越来越复杂,前端和后端之间也有区别,其中前端更偏向于屏幕呈现、UI (用户体验)、用户流、不同设备的运行版本......等等。
后端更多的是功能实现,包括数据库管理、登录、注册......等等。

后来针对前端越来越复杂的情况,也开始有了框架的概念,目前流行的三大框架分别是 React、Vue、Angular。

例如,不同的框架也会有不同的 "状态管理 "方式:
React:基本上,你只需管理数据,并根据 "状态 "进行渲染。
Vue:"数据与组件的 "双向绑定

根据 React 框架,可大致分为以下几类

Local State

    • useState

    • useReducer

Context

    • useContext

第三方

    • Redux

    • Mobx

    • Zustand

由此可见,React 框架中的 "状态管理 "已经相当复杂。

因此,本文只着重介绍 Zustand,并将使用实际例子来介绍它。

我们还可以通过比较以下软件包的总下载量,了解 Redux、Mobx 和 Zustand 在过去一年中的受欢迎程度。

Zustand npm doanload

 

https://npmtrends.com/mobx-vs-react-redux-vs-zustand


什么是 Zustand?

根据 Zustand 的说法,这是一个轻量级、快速的 "状态管理 "套件,基于 Flux 和 Hook 概念。

附注:上面的熊是 Zustand 的标志性吉祥物!

Zustand 还设计用于解决复杂的 React 状态管理问题,如僵尸子问题、React 并发、上下文丢失等。

如果您想进一步了解这些问题,可以参考以下链接

Zombie Child Problem:React Redux 文档

React Concurrency:官方 React 文档

React Context Loss:Stack Overflow

我们还可以通过 Zustand 的官方网站了解他们击败 Redux 的雄心壮志。


Zustand 使用

以下两种简单用法适用于 JavaScript 用户

创建第一个 Store

Zustand 基于 Hook 构建,因此创建的第一个存储空间是由自定义钩子创建的存储空间,它可以包含变量、对象和函数等。第一个创建的存储空间是自定义钩子创建的存储空间,它可以包含变量、对象和函数等。您还可以通过 Set 和 Get 对数据进行 "状态管理"。

				
					import create from 'zustand' const useBearStore = create((set) => ({ bears: 0, increasePopulation: () => set((state) => ({ bears: state.bears + 1 })), removeAllBears: () => set({ bears: 0 }), }))
				
			
组件的绑定

由于它使用钩子,因此可以直接加载到任何组件中使用。
这些状态也可以呈现,这对 Zustand 来说是一大福音,因为您可以看到只需几行字就可以完成。

下面是一个简单的 Zustand 示例,供 TypeScript 用户参考。

				
					function BearCounter() {   const bears = useBearStore((state) =&gt; state.bears)   return <h1><span class="ez-toc-section" id="bears-around-here"></span>{bears} around here ...<span class="ez-toc-section-end"></span></h1>
} function Controls() {   const increasePopulation = useBearStore((state) =&gt; state.increasePopulation)   return <button onclick="{increasePopulation}">one up</button>
}

				
			

Zustand TypeScript 写法

在 Zustand 中,我们将使用创建来创建一个新商店。 
输入函数,通过钩子传回状态,然后重新渲染。

				
					import create from "zustand" type Product = { sku: string; name: string; image: string } type CartState = {   products: Product[]   cart: { [sku: string]: number }   addToCart: (sku: string) = > void   removeFromCart: (sku: string) => void } // Selectors // ... // Initialize our store with initial values and actions to mutate the state export const useCart = create<CartState>(set => ({ products : [ // ... ], cart: {}, // Actions // ... }))
				
			

在此,我们还展示了 Redux 和 Mobx 的编写方式,以便读者比较两者的不同之处,但本文将不关注 Redux 或 Mobx,只关注 Zustand 及其状态管理。

Redux TypeScript 写法

				
					import { createSlice, configureStore, PayloadAction } from "@reduxjs/toolkit" import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux" // Slices // Definee the shape of the state and how to mutate it type ICart = { [ sku: string]: number } const cartInitialState: ICart = {} const cartSlice = createSlice({   name: "cart",   initialState: cartInitialState,   reducers: {   // ...   }, }) type IProduct = { sku: string; name: string; image: string } const productsInitialState: IProduct[] = [   // ... ] const productsSlice = createSlice({   name: "products",   initialState: productsInitialState,   reducers: {}, }) // Actions // ... // Selectors // ... // Store export const store = configureStore({   reducer: {   cart: cartSlice.reducer,   products: productsSlice.reducer,   }, }) // ... const App = () => { return (   <Provider store={store}>   <NavigationContainer>   <Stack.Navigator>{/* ... */}</Stack.Navigator>   <StatusBar style="auto" />   </NavigationContainer>   < /Provider>   ) }
				
			

Mobx TypeScript 写法

				
					import { types, Instance } from "mobx-state-tree" const Product = types.model({ sku: types.string, name: types.string, image: types.string, }) // Model and type our data with mobx state tree const CartStore = types .model("CartStore", { products: types.array(Product), cart: types.map(types.number), }) // Actions to mutate the state .actions(store => ({ // ... })) // Views are like selectors .views(self => ({ // ... })) type CartStoreType = Instance<typeof CartStore> // Spin up a hook to use our store and provide initial values to it let _cartStore: CartStoreType export const useCart = () => { if (!_cartStore) { _cartStore = CartStore.create({ products: [ // ... ], cart: {}, }) } return _cartStore }
				
			

Zustand 能否超越 Context 和 Redux?

 

https://github.com/pmndrs/zustand#why-zustand-over-redux

根据 Zustand 官方的说法,在此列出并简要说明上述要点。

Redux

Redux 本身是一个更复杂的状态管理工具,会有 Actioins、View 和 State 流程。

以下是 Redux 官方数据流示意图,可以看出,如果想从头开始使用 Redux 的状态管理工具,学习门槛相对较高。

Redux Data Flow

 

Redux Data Flow

Redux Data Flow and React Component Life Cycle
几乎所有想学习 Redux 的人都见过这张图片。对我来说,这很简单,但...dev.to

Context

上下文本身被归类为状态管理,但实际上它更像是一种集中触发状态的方式。

与 Zustand 相比,它不容易管理,因为它分散在不同的文件中。

Context Data Flow

 

Context Data Flow

[React] Context API
要在 React 中管理数据,您可以使用 Props、State 和 Context。在这篇博文中,我将介绍 Context 是什么...dev-yakuza.posstree.com


结论

使用该技术的优势

有了 Zustand,您就可以分解复杂业务逻辑的数据和逻辑,并对其进行建模。除了提高可读性,它还能让编写测试变得更容易。

使用心得

Zustand 本身就是一个充满易学性的状态管理工具,自己在工作产品中使用也比较方便,包括对状态进行 Set、Get 或者在组件中使用都比较方便,完全推荐给想要针对 React 进行状态管理的读者。

感谢您的收看 ~ 如果您有任何疑问或想讨论上述任何问题,请随时留言或给我发私人信息!

引用

https://github.com/pmndrs/zustand

https://react-redux.js.org/api/hooks#stale-props-and-zombie-children

https://docs.pmnd.rs/zustand/getting-started/comparison

其他文章参考

大公司为何使用 Nx?Monorepo 工具 5 分钟快速构建

你真的了解 Monorepo 吗?5 分钟了解前端大型架构。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

zh_CN简体中文