当前位置: 首页 > Web前端 > JavaScript

zustand状态管理源码解析(一)

时间:2023-03-26 21:09:49 JavaScript

React状态管理的工具库很多。比较有名的是redux和mobx。这两个工具库使用比较广泛。今天我们要了解的是一个比较小巧精致的状态管理工具库zustand。到目前为止有17+开始。最重要的是这个库提供的store写起来简单。无需通过state、action、dispatch等一系列繁琐的操作来管理状态,也可以不用组件来使用。让我们一起阅读首先阅读源码了解其状态管理机制;本次先从3.x版本开始解读,4.x版本的作者还在rc阶段,最终发布后我们会继续补充4.x版本的变化分析;1.Create创建store相对于使用工具库来说非常简单,我们直接使用importcreatefrom'zustand'interfaceBearStore{bears:number,increasePopulation:()=>void,removeAllBears:()=>void}constuseBearStore=create(set=>({bears:0,increasePopulation:()=>set(state=>{console.log('fordebug')return{bears:state.bears+1}}),removeAllBears:()=>set({bears:0})}))projectimportuseBearStorefrom'./BearStore'constHome:React.FC=()=>{constbearStore=useBearStore()return

内容信息
{bearStore.bears}
增加Reset
}我们会在使用中对create函数的使用进行详细的说明,我们来解读一下源码中create函数的说明//说明源码中的create函数,constcreate=((createState:StateCreator|undefined)=>{returncreateState?createImpl(createState):createImpl})asCreate//createState参数定义exporttypeStateCreator=((setState:Get,Mis>,'setState',undefined>,getState:Get,Mis>,'getState',undefined>,存储:Mutate,Mis>,$$storeMutations:Mis)=>U)&{$$storeMutators?:Mos}关于createState类型的定义有很多描述。本期我们简单说一下用法;useStore,返回一个useStorehooks,通过react组件中的useStore(selector)可以选择性的获取对应的storeslice。看看上面的内容是如何实现的;2.理解源码的创建流程经过一系列的源码分析和学习,这里总结出一张create的执行流程图。通过这张图,我们一步步分析它的实现过程。参考图如下:简单来说,分为以下几个步骤:1.通过create(set,get)=>({xxxx})传入一个建store的方法;2.在create函数内部,通过createStore创建一个statemanagementstore(通俗点讲就是闭包);3、createStore除了创建store之外,还返回如下内容,返回setState方法,setState方法更新值时,遍历监听订阅事件列表;返回getState方法获取store对应的值;返回订阅方法以注入订阅事件;返回destroy方法清除订阅事件列表;4.在create方法体中,继续创建一个useStorehooks,返回react组件获取store,关于useStore主要处理以下事情:获取store存储的内容(具体我们可以通过storeslice获取)useStore(selector,enqlity))的第一个参数通过useEffect或useLayoutEffect初始化组件存储值,并将状态变化事件注入监听器;下图是其zustand状态管理全过程的总结。可以参考一下:3、手写一个toy级的zustand上面我们分析了zustand的执行过程和状态管理,接下来我们尝试手写toyzustand。我们将这部分分为两部分,一是创建store部分,二是创建useStorehooks部分,如下:functioncreateStore(createState){letstate;让listeners=newSet();//获取存储内容constgetState=()=>state;//更新存储内容constsetState=(partial,replace)=>{constnextState=typeofpartial==='函数'?部分(状态):部分;if(nextState!==state){constprevState=state;状态=替换?nextState:Object.assign({},state,nextState);listeners.forEach(listener=>listener(state,prevState));}}//添加订阅信息constsubscribe=(listener)=>{listeners.add(listener);//清除订阅信息return()=>{listeners.delete(listener);};}//清除所有监听器constdestroy=()=>listeners.clear();constapi={getState,setState,destroy,subscribe};//创建初始状态state=createState(setState,getState,api);returnapi;}exportdefaultcreateStoregenerateshooks方法import{useLayoutEffect}from"react";从“反应”导入{useReducer,useRef};importcreateStorefrom"./createStore";functioncreate(createState){//根据createStore和createState创建一个storeconstapi=createStore(createState);/***@descriptioncreatehooks*@param{Function}选择器可选,返回存储内容,默认api.getState*@param{Function}enqulityFn可选,默认为Object.is判断*@returns*/constuseStore=(selector=api.getState,enqulityFn=Object.is)=>{//生日forceUpdate函数const[,forceUpdate]=useReducer(c=>c+1,0);conststate=api.getState();conststateRef=useRef(状态);//存储方法constselectorRef=useRef(selector);constenqlityFnRef=useRef(enqulityFn);//当前状态存储letcurrentStateRef=useRef();如果(currentStateRef.current===undefined){currentStateRef.current=选择器(状态);/***当前用户需要的stateslice(这部分需要注意,zustand用户可以根据selector获取部分storecontent值)*所以我们判断是否需要更新,比较内容切片,而不是整个商店*/letnewStateSlice;//更新标志lethasNewStateSlice=false;if(stateRef.current!==state||选择器!==selectorRef.current||enqulityFn!==enqulityFnRef.current){newStateSlice=selector(state);hasNewStateSlice=!enqulityFn(newStateSlice,currentStateRef.current);}//初始化数据useLayoutEffect(()=>{if(hasNewStateSlice){currentStateRef.current=newStateSlice;}stateRef.current=state;selectorRef.current=selector;enqulityFnRef.current=enqulityFn;})//添加状态变化订阅eventuseLayoutEffect(()=>{constlistener=()=>{//获取最新状态值constnextState=api.getState();//获取当前用户需要的storesliceconstnextStateSlice=selectorRef.current(nextState);//比较当前用户的当前切片和最新的store切片是否相同,如果不相同则更新到最新的切片if(!enqulityFnRef.current(nextStateSlice,currentStateRef.current)){stateRef.current=nextState;currentStateRef.current=nextStateSlice;强制性升级();}}constunSubscribe=api.subscribe(listener);//当组件被销毁时,我们需要取消订阅returnunSubscribe},[]);//返回用户需要的切片constsliceToReturn=hasNewStateSlice?newStateSlice:currentStateRef.current;返回sliceToReturn;}//暴露修改store的方法{getState,setState,destroy,subscribe}使用户脱离react组件使用状态管理//例子:useStore.getState()....Object.assign(使用商店,API);returnuseStore;}exportdefaultcreateprojectusemethod://createstoreimportcreatefrom'../create'exportconstuseCounterStore=create(set=>({count:0,increment:()=>设置(state=>({count:state.count+1})),}))//项目中使用的方法importReactfrom'react';从'./store'导入{useCounterStore};const其他=()=>{constcounter=useCounterStore();return(

Other

{counter.count}
);}exportdefaultOther;这个先到这里吧,觉得还不错的话请点赞关注支持一下~