在我们前端开发中,一定会接触现在最热门的几大框架(Vue, React等等),在使用框架的过程中,我们一定会接触某些状态管理工具。

抚顺县网站制作公司哪家好,找成都创新互联公司!从网页设计、网站建设、微信开发、APP开发、成都响应式网站建设等网站项目制作,到程序开发,运营维护。成都创新互联公司于2013年开始到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联公司。
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个状态:
View:视图层
Action(动作):视图层触发的动作 or 行为
Dispatcher(派发器):收集触发行为,进行统一管理,统一分发给store层。
Store(数据层):用来存放应用的状态,根据dispatcher触发行为,就提醒Views要更新页面
要是同学了解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 (
 - <>
 - >
 - )
 - }
 - function Son() {
 - return
 - }
 - function Counter() {
 - const { state, dispatch } = useContext(Context);
 - return (
 - {state}
 - )
 - }
 - export default Parent;
 - 复制代码
 
Vue响应式数据 + vue.Provide/inject
使用vue响应式系统 + provide/inject API来实现一个具有穿透性的局部状态管理
- // Parent.vue
 - 复制代码
 
- // Son.vue
 - 复制代码
 
- // Counter.vue
 - {{ store.data.count }}
 - 复制代码
 
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 (
 - {count}
 - )
 - })
 - export default Counter;
 - 复制代码
 
用有限状态机去思考某些线性状态场景的数据管理。
在之前的业务开发的时候,就会出现一个痛点,应用全局状态管理非常臃肿。
在不断功能迭代的过程中,需要做不同的状态管理,虽然都是对同一份数据进行维护,但维护的方式不同,进行一次状态更新就需要编写一个不同的dispatch函数。随着业务需求的增加,dispatch函数越来越多,难以管理和复用。
思考如何解决这个问题的时,偶然看到了有限状态机相关文章,思考到应用的功能模块在某一个时刻是相互独立的,我们在局部将数据进行更新,之后用一个全局函数对数据进行统一替换。
注:本文为探索性质,使用原生组件进行局部管理不需要引入依赖。但使用第三方工具造成包体积大小的增加,是否会增加性能消耗有待讨论
                网站栏目:前端:从状态管理到有限状态机的思考
                
                浏览路径:http://www.csdahua.cn/qtweb/news8/160358.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网