在我们前端开发中,一定会接触现在最热门的几大框架(Vue, React等等),在使用框架的过程中,我们一定会接触某些状态管理工具。
Vue我们会使用Vuex来管理全局状态, React会使用Redux来管理。
首先是不是,在问为什么?
在使用类似Vue,React框架时,我们一定会使用状态管理吗?这个答案是肯定的。或许我不会主动去使用Vuex, Redux,但我们编写每一个组件的时候就已经在管理状态,Vuex, Redux只是更方便我们进行全局的状态管理。
为什么一定会使用状态管理?这是因为现代前端框架使用数据驱动视图的形式来描述页面。比如,Vue、 React组件会有一个自己内部,外部的状态来共同决定组件的如何显示的,用户与组件交互导致数据变更,进而改变视图。
框架 | 内部状态 | 外部状态 |
---|---|---|
Vue | data | props |
React | state, useState | props |
所以我们所写大部分业务逻辑,是在管理状态,框架会帮我们状态映射成视图,这可以说是很经典的MVVM模式。
View?=?ViewModel(Model);?//?视图?=??状态?+?管理?复制代码?
其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。
我们来理解一下上面这段话。
状态机有基本几个要素:
上面这张图所描述的状态机,我们使用js对象来进行描述
const?stateTool?=?{???//?当前状态???currentState:?'1',??????//?状态转变函数???transition:?(event)?=>?{???switch(event.type)?{???????case?'1':?{?????????this.currentState?=?event.status;?????????doSomething1();?????????break;???????}???????case?'2':?{?????????this.currentState?=?event.status;?????????doSomething2();?????????break;???????}???????case?'3':?{?????????this.currentState?=?event.status;?????????doSomething3();?????????break;???????}???????default:??????????console.log('Invalid?State!');?????????break;?????}???}?}?复制代码?
Flux是什么?Flux是一个Facebook开发的、利用单向数据流实现的应用架构
简单说,Flux 是一种架构思想,专门解决软件的结构问题。可以说他是有限状态机的另外一种形式。
一个Flux管理分为4个状态:
要是同学了解flux的的工作流程,那么很容易就发现这是一种工程化的状态机。
我们通过store 存放的是初始化状态,这种初始化状态数据可以页面初始化时设定 或 页面加载时请求后端接口数据,来初始化store数据。
通过store的初始化数据,来构建初始化的视图层。
根据视图层的行为会触发action,我们通过统一的dispatcher来收集action, dispatcher将行为派发给store。
store通过判断事件的类型 和 payload,来修改内部存储状态。达到状态转移的目的,并统一提醒view层更新页面;
既然我们是通过数据状态来管理视图的,那么在设计初期我们就可以从有限的状态转移来思考业务逻辑。通过思考每个状态对应的数据,状态转移函数,我们可以很清晰的罗列出数据更变逻辑。从数据去控制视图也是现代前端所接触到的MVVM模式。
一个大型应用,我们也会使用Vuex 或 Redux来进行一整个应用的管理。
在平时的业务中,我们会遇到一个痛点是:Vuex,Redux是一个全局状态管理,但我们现在需要在局部需要一个局部状态管理变更,只能使用?mutation
?或?dispatch
?去提交更改。
如果我们频繁的更新状态,那么我们需要为每一个局部模块编写大量dispatch函数来间接修改全局状态。随着应用的扩充,dispatch文件会越来越臃肿。
那么我们是不是可以使用不同的状态管理工具,来实现局部状态的管理。在局部状态更新完之后,再去用局部更新去更新全局呢?
注:但这也会有一个缺点,局部管理相对独立。有些高度复用的提交函数需要放在全局状态管理上
React Hooks +?React.createContext
React Hooks提供了useReducer + useContext + Context 可以实现一个小型的状态管理
//?以下代码就实现了一个能够穿透组件的状态管理?import?React,?{?useReducer,?useContext?}?from?'react';??const?reducer?=?(state?=?0,?{?type,?...payload?})?=>?{???switch?(type)?{?????case?'add':???????return?state?+?1;?????case?'desc':???????return?state?-?1;?????default:???????return?state;???}?}??const?Context?=?React.createContext();?const?Parent?=?()?=>?{???const?[state,?dispatch]?=?useReducer(reducer,?0);???return?(?????<>???????<Context.Provider?value={{?state,?dispatch?}}>?????????<Son?/>???????</Context.Provider>?????</>???)?}??function?Son()?{???return?<Counter?/>?}??function?Counter()?{???const?{?state,?dispatch?}?=?useContext(Context);???return?(?????<div>???????<button?onClick={()?=>?dispatch({?type:?'desc'?})}>-</button>???????{state}???????<button?onClick={()?=>?dispatch({?type:?'add'?})}>+</button>?????</div>???)?}?export?default?Parent;?复制代码?
Vue响应式数据 + vue.Provide/inject
使用vue响应式系统 + provide/inject API来实现一个具有穿透性的局部状态管理
//?Parent.vue?<template>???<Son?/>?</template>??<script?setup>?import?{?provide,?reactive,?readonly?}?from?"vue";?import?Son?from?"./Son.vue";?const?data?=?reactive({???count:?0,?});?const?onAdd?=?()?=>?{???data.count++;?};?const?onDesc?=?()?=>?{???data.count--;?};?provide("store",?{???data:?readonly(data),?//?只读属性???onAdd,?//?修改函数add???onDesc,?//?修改函数desc?});?</script>??复制代码?
//?Son.vue?<template>???<Counter?/>?</template>??<script?setup>?import?Counter?from?"./Counter.vue";?</script>?复制代码?
//?Counter.vue?<template>???<div>?????<button?@click="store.onDesc">-</button>?????{{?store.data.count?}}?????<button?@click="store.onAdd">+</button>???</div>?</template>??<script?setup>?import?{?inject?}?from?"vue";?const?store?=?inject("store",?{});?//?穿透读取store?</script>?复制代码?
Xstate是一个很有趣的类似有限状态机的状态管理,?Xstate
?着重点在于?管理状态?,通过?状态转换去维护数据?。
我们来定义一个简单的promise状态机,使用官方提供的工具进行可视化
import?{?Machine?}?from?'xstate';??//?创建状态机?const?promiseMachine?=?Machine({???id:?'promise',?//?唯一id???initial:?'pending',?//?初始化状态???states:?{?//?状态集合?????pending:?{???????on:?{?????????RESOLVE:?'resolved',?????????REJECT:?'rejected',????}?????},?????resolved:?{???????type:?'final',?????},?????rejected:?{???????type:?'final'?????}???}?})?复制代码?
Xstate有提供函数来实现状态机服务,实现拥有状态的实体
import?{?interpret?}?from?'xstate'?const?promiseService?=?interpret(promiseMachine).onTransition(state?=>????console.log(state.value)?)?//?创建服务,指定状态转移时回调函数?promiseService.start()?//?启动服务?promiseService.send('RESOLVE');?//?通知服务转移状态,并执行回调函数?复制代码?
mobx是一种响应式的状态管理,他所提倡的是拆分store做数据管理。这就很适合做局部的状态管理,根据局部状态管理来更新全局状态。
相同的,我们举个例子
import?{?action,?autorun,?observable?}?from?'mobx'?import?{?observer?}?from?'mobx-react'?import?React?from?'react'??const?appStore?=?observable({?//?建立store???count:?0,???age:?18,?})??//?autorun?只会观察依赖的相关数据?//?使用当appStore.age更新时,才会触发该函数?autorun(()?=>?{???//?doSomething();???console.log('autorun',?appStore.age);?})??const?Counter?=?observer(()?=>?{???const?{?count?}?=?appStore;???const?onAdd?=?action(()?=>?{?//?使用action更新store数据?????appStore.count++;???})???const?onDesc?=?action(()?=>?{?????appStore.count--;???})???return?(?????<div>???????<button?onClick={onDesc}>-</button>???????{count}???????<button?onClick={onAdd}>+</button>?????</div>???)?})??export?default?Counter;?复制代码?
注:本文为探索性质,使用原生组件进行局部管理不需要引入依赖。但使用第三方工具造成包体积大小的增加,是否会增加性能消耗有待讨论
领取专属 10元无门槛券
私享最新 技术干货