当前位置: 首页 > news >正文

简单又强大的Zustand,为啥不自己手写一个呢

谈起react的状态管理库,大家肯定会想到redux,用过redux的人肯定会发现,它使用起来是非常的繁琐,受人诟病。

后起之秀的react的管理库就有zustand jotai等,其中最为简单且流行的就是 zustand,它可以说是操作简单,功能强大,redux的任何功能他都可以实现,并且可以更简单的实现。

我们先来简单看一下 zustand使用方法。

  • 安装 npm install zustand
import { create } from 'zustand'type BearState = {bears: numberincreasePopulation: () => void
}const useBearStore = create<BearState>((set, get, api) => ({bears: 0,increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
}))export default useBearStore;

我们可以看到三个参数,set get api他们分别是后去设置state,获取state,api是有关state方法的数据。

在这里插入图片描述

其中的getState和setState就是上述的中的get set

在App.tsx中使用

import useBearStore from "./zustand/baseStore";function App() {const bears = useBearStore(state => state.bears)const increasePopulation = useBearStore(state => state.increasePopulation)return (<div>{bears}  <button onClick={increasePopulation}>+ 1</button></div>);
}export default App;

使用方式很简单,只需要创建一个store,使用的时候用 useBearStore传入一个回调,返回需要的数据即可。

在zustand中另一个实用的凡是subscribe,添加一个监听器,在state变化的时候会执行传入的回调函数。

    import useBearStore from "./zustand/baseStore";import { useEffect } from "react";function App() {const bears = useBearStore(state => state.bears)const increasePopulation = useBearStore(state => state.increasePopulation)useEffect(() => {//监听state的变化useBearStore.subscribe((state, prevState) => {console.log(state, prevState);})}, []);return (<div>{bears}  <button onClick={increasePopulation}> + 1</button></div>);}export default App;

使用起来是不是很简单,redux中需要自己定义action,reducer ,然后在把action导出,要繁杂的不少。

那我们如何写一个zustand,其实zustand的原理很简单,包括源码都没有多少。

那我们如何自己写一个呢!

在这里插入图片描述

首先就是create方法接受一个回调函数,回调函数中接口set get api这么几个参数,并返回初始数据

所以写一个create方法


function create(initialState) {let state;//replace 是否替换function setState(partial, replace) {if(replace) {//直接替换  state = partial;} else {//合并老数据state = { ...state, ...partial };}}function getState() {return state;}const api = { setState, getState };state = initialState(setState, getState);}

之后返回的值要能通过回调返回用户想要的数据。
在这里插入图片描述

继续补全代码

function create(initialState) {let state;//replace 是否替换function setState(partial, replace) {if(replace) {//直接替换  state = partial;} else {//合并老数据state = { ...state, ...partial };}}function getState() {return state;}const api = { setState, getState };state = initialState(setState, getState);return (func) => {//执行函数将state当作参数传入const result = func(api.getState());return result;}
}

现在我们在继续完善subscribe订阅操作

订阅操作就是在state变化的时候,调用相应的回调

在这里插入图片描述

只要又setState的时候state会变化,所以我们只需要在封装setState方法即可,在setState的时候去对比一下前后数据,如果数据变化了则执行回调函数。

在这里插入图片描述

代码如下

function create(initialState) {let state;//监听器(存放回调函数)const listeners = new Set();//replace 是否替换function setState(partial, replace) {//获取到最新的stateconst nextState = typeof partial === 'function' ? partial(state) : partial;// 数据有变化if (!Object.is(nextState, state)) {//记录旧的stateconst previousState = state;//更新stateif (replace) {state = nextState;} else {state = { ...state, ...nextState };}//执行记录的回调函数listeners.forEach((listener: any) => listener(state, previousState));}}//增加订阅方法function subscribe(listener) {listeners.add(listener);}//增加移除调用的方法,如果组件卸载了,那么他的相关订阅也许删除function unsubscribe(listener) {listeners.delete(listener);}function getState() {return state;}const api = { setState, getState , subscribe};state = initialState(setState, getState);const useBoundStore = (func) => {const result = func(state);return result;}//我们知道返回值是一个函数,但是它又可以调用subscribe这种api所以我们需要将api挂载到返回的函数中//函数是一个对象,使用Object.assign将api挂载到返回的函数中return Object.assign(useBoundStore, api);
}

我们都知道如果组件中使用的state的数据变化肯定是要刷新的,谁又能监听到state的变化呢,这不正好是我们刚写的subscribe吗
在这里插入图片描述

代码如下

import { useEffect } from "react";import { useState } from "react";function create(initialState) {let state;//监听器(存放回调函数)const listeners = new Set();//replace 是否替换function setState(partial, replace) {//获取到最新的stateconst nextState = typeof partial === 'function' ? partial(state) : partial;// 数据有变化if (!Object.is(nextState, state)) {//记录旧的stateconst previousState = state;//更新stateif (replace) {state = nextState;} else {state = { ...state, ...nextState };}//执行记录的回调函数listeners.forEach((listener: any) => listener(state, previousState));}}//增加订阅方法function subscribe(listener) {listeners.add(listener);}//取消订阅function unsubscribe(listener) {listeners.delete(listener);}function getState() {return state;}const api = { setState, getState , subscribe, unsubscribe};state = initialState(setState, getState);const useBoundStore = (func) => {//增加一个useState,这样调用forceUpdate就可以自己控制组件是否刷新const [_, forceUpdate] = useState(0);useEffect(() => {//只要增加一个订阅,在state变化的时候看一下func返回值是否变化即可const listener = subscribe((state, previousState) => {//变化了则强制刷新if (func(state) !== func(previousState)) forceUpdate(Math.random());});return () => {//组件卸载的时候取消订阅unsubscribe(listener);}}, []);const result = func(state);return result;}//我们知道返回值是一个函数,但是它又可以调用subscribe这种api所以我们需要将api挂载到返回的函数中//函数是一个对象,使用Object.assign将api挂载到返回的函数中return Object.assign(useBoundStore, api);
}

我们只需要在useBearStore的时候增加一个监听,在state变化的时候调用回调函数,回调函数中判断属性是否变化即可。

在这里插入图片描述

这样就能实习一个zustand了,是不是很简单。

然后替换成自己的手写的zustand试试

import useBearStore from "./zustand/baseStore";
import { useEffect } from "react";
function App() {const bears = useBearStore(state => state.bears)const increasePopulation = useBearStore(state => state.increasePopulation)useEffect(() => {useBearStore.subscribe((state, prevState) => {console.log(state, prevState);})
}, []);return (<div>{bears}  <button onClick={increasePopulation}> + 1</button></div>);
}export default App;

在这里插入图片描述

完全没问题,源码也是这个思路。

看完这篇你文章是不是发现原来高高在上的库也不过如此。


http://www.mrgr.cn/news/92082.html

相关文章:

  • 虚拟机emulator报错
  • C# 将非托管Dll嵌入exe中(一种实现方法)
  • Windows10系统本地部署Ollama_DeepSeek-R1实操手册
  • leetcode 119. 杨辉三角 II
  • 【数据结构】(11) Map 和 Set
  • 洛谷P1135多题解
  • vue3 Props的使用
  • Web自动化之Selenium实战案例1:论文pdf自动下载
  • 《离线唤醒+离线Vosk识别+DeepSeek+离线合成,你的第二大脑》
  • PTA习题(C语言)
  • 如何在 Mac 上安装并配置 JDK 环境变量
  • dify实现分析-rag-内容检索rerank的两种实现
  • 详细介绍STM32(32位单片机)外设应用
  • 垂类大模型微调(二):使用LLaMA-Factory
  • CSDN博客写作教学(一):初识markdown编辑器(纯干货)
  • Docker 自制镜像:Ubuntu 安装 samba+Webmin
  • 特辣的海藻!2
  • Linux7-线程
  • Mac本地部署DeepSeek-r1如何设置文档知识库
  • SOME/IP-SD -- 协议英文原文讲解1