赞
踩
当下前端流行的框架,都是用状态来描述界面(state => view),可以说前端开发实际上就是在维护各种状态(state),这已经成为目前前端开发的共识。
复制代码
View = ViewModel(Model);
理想情况下,ViewModel 是纯函数,给定相同的 Model,产出相同的 View。
state => view 很好理解,但如何在 view 中合理地修改 state 也是一个问题。
图书馆的管理,原来是开放式的,所有人可以随意进出书库借书还书,如果人数不多,这种方式可以减少流程,增加效率,一旦人数变多就势必造成混乱。
Flux 就像是给这个图书馆加上了一个管理员,所有借书还书的行为都需要委托管理员去做,管理员会规范对书库的操作行为,也会记录每个人的操作,减少混乱的现象。
我们寄一件东西的过程
没有快递时:
有了快递公司:
多了快递公司,让快递公司给我们送快递。
当我们只寄送物品给一个朋友,次数较少,物品又较少的时候,我们直接去朋友家就挺好的。但当我们要频繁寄送给很多朋友很多商品的时候,问题就复杂了。
软件工程的本质即是管理复杂度。使用状态管理类框架会有一定的学习成本而且通常会把简单的事情做复杂,但如果我们想做复杂一点的事情(同时寄很多物品到多个不同地址),对我们来说,快递会让复杂的事情变的简单。
这同时也解释了,是否需要添加状态管理框架,我们可以根据自己的业务实际情况和技术团队的偏好而添加,有些情况下,创建一个全局对象就能解决很多问题。
Redux store 是单一数据源。Redux 没有 dispatcher 的概念,转而使用纯函数(pure function)代替。
Redux store 是不可变的(Immutable)。
和 Redux 对单向数据流的严格规范不同,Mobx 只专注于从 store 到 view 的过程。在 Redux 中,数据的变更需要监听,而 Mobx 的数据依赖是基于运行时的,这点和 Vuex 更为接近。
Facebook 提出了 Flux 架构思想,规范了数据在应用中的流动方式。其基本架构如下入所示,其核心理念是单向数据流,它完善了 React 对应用状态的管理。
上图描述了页面的启动和运行原理:
1.通过 dispatcher 派发 action,并利用 store 中的 action 处理逻辑更新状态和 view
2.而 view 也可以触发新的 action,从而进入新的步骤 1
其中的 action 是用于描述动作的简单对象,通常通过用户对 view 的操作产生,包括动作类型和动作所携带的所需参数,比如描述删除列表项的 action:
复制代码
{ type: types.DELETE_ITEM, id: id };
而 dispatcher 用于对 action 进行分发,分发的目标就是注册在 store 里的事件处理函数:
复制代码
dispatcher.register(function(action) { switch (action.type) { case "DELETE_ITEM": sotre.deleteItem(action.id); //更新状态 store.emitItemDeleted(); //通知视图更新 break; default: // no op } });
store 包含了应用的所有状态和逻辑,它有点像传统的 MVC 模型中的 model 层,但又与之有明显的区别,store 包括的是一个应用特定功能的全部状态和逻辑,它代表了应用的整个逻辑层;而不是像 Model 一样包含的是数据库中的一些记录和与之对应的逻辑。
参考链接:flux
原生 Redux API 最简单的用例
复制代码
function counter(state, action) { if (typeof state === "undefined") { return 0; } switch (action.type) { case "INCREMENT": return state + 1; case "DECREMENT": return state - 1; default: return state; } } var store = Redux.createStore(counter); // var valueEl = document.getElementById("value"); function render() { valueEl.innerHTML = store.getState().toString(); } render(); store.subscribe(render); document.getElementById("increment").addEventListener("click", function() { store.dispatch({ type: "INCREMENT" }); }); document.getElementById("decrement").addEventListener("click", function() { store.dispatch({ type: "DECREMENT" }); }); document.getElementById("incrementIfOdd").addEventListener("click", function() { if (store.getState() % 2 !== 0) { store.dispatch({ type: "INCREMENT" }); } }); document.getElementById("incrementAsync").addEventListener("click", function() { setTimeout(function() { store.dispatch({ type: "INCREMENT" }); }, 1000); });
应用中所有的 state 都以一个对象树的形式储存在一个单一的 store 中。 改变 state 的唯一办法是触发 action,一个描述发生什么的对象。 为了描述 action 如何改变 state 树,你需要编写 reducers。
单一数据源
整个应用的 state
被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store
中。
state 是只读的
唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。
使用纯函数来执行修改
为了描述 action 如何改变 state tree ,你需要编写 reducers
。 改变 state
的惟一方法是 dispatch action
。你也可以 subscribe
监听 state
的变化,然后更新 UI。
严格的单向数据流是 Redux 架构的设计核心。
Redux 的 API 非常少。
Redux 定义了一系列的约定(contract)来让你来实现(例如 reducers),同时提供少量辅助函数来把这些约定整合到一起。
Redux 只关心如何管理 state。在实际的项目中,你还需要使用 UI 绑定库如 react-redux。
在写 redux 的 action 的时候,总是需要用到扩展语句或者 Object.assign()
的方式来得到一个新的 state,这一点对于 JavaScript 而言是对象的浅拷贝,它对内存的开销肯定是大于 mobX 中那样直接操作对象属性的方式大得多。
参考链接:redux-immutable seamless-immutable reselect 为什么使用 Redux 管理状态是可预测的
redux 是 react 技术栈中的状态控制流框架,使用了标准的函数式思想,期望(强制)所有状态管理都是纯函数。这也意味着各状态之间都是独立的。但是有一类状态 redux 直接甩给了的第三方模块,副作用模块 redux-saga
也就成了任劳任怨的典型代表。副作用正是因为不确定性和可变性而得名,而其给出的状态又是相互影响,如何解耦使得原本复杂的非线性呈现为线性逻辑,正是有限状态机的用武之处。
dva 首先是一个基于 redux
和 redux-saga
的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router
和 fetch
,所以也可以理解为一个轻量级的应用框架。
在 redux 的生态圈内,每个环节有多种方案,比如 Data 可以是 immutable 或者 plain object,在你选了 immutable 之后,用 immutable.js 还是 seamless-immutable,以及是否用 redux-immutable 来辅助数据修改,都需要选择。
MobX 是一个用法简单优雅、同时具有可扩展性的状态管理库。
复制代码
import { observable, autorun } from "mobx"; const appState = observable({ counter: 0, add(value) { this.counter += value; } }); autorun(() => console.log(appState.counter)); setInterval(() => appState.add(1), 1000);
在 mobx 中我们可以直接修改状态
复制代码
import { observable } from "mobx"; const appState = observable({ counter: 0 }); appState.counter += 1;
可以通过引入 Strict 模式来避免这种不良好的实践:
复制代码
import { useStrict } from "mobx"; useStrict(true);
MobX 脱胎于响应式编程(Reactive Programming),其核心思想为 Anything that can be derived from the application state, should be derived. Automatically,即避免任何的重复状态。
MobX 中核心的概念即是 Observable,相信接触过响应式编程的肯定非常熟悉,从后端的典型代表 RxJava 到 Android/iOS 开发中的各种响应式框架都各领风骚。
Redux / MobX 均为客户端开源状态管理库,用状态来描述 UI 界面,它们与 React 都不具有强绑定关系,你也可以配合别的框架来使用它们。 当然,与 React 是再合适不过的了,React 作为 View 层的框架,通过 Virtual DOM 机制来优化 UI 渲染,Redux / MobX 则提供了将相应状态同步到 React 的机制。
Redux 与 MobX 的不同主要集中于以下几点:
shouldComponentUpdate
优化。而 MobX 只自动更新你所关心的,不必担心嵌套带来的重渲染问题。Mobx 最关键的函数在于 autoRun,autoRun 的专业名词叫做依赖收集,也就是通过自然的使用,来收集依赖,当变量改变时,根据收集的依赖来判断是否需要更新。Mobx 使用了 Object.defineProperty
拦截 getter 和 setter,和 Vue 一样。
Vuex 是专门为 Vue.js 设计的状态管理库。把组件的共享状态抽取出来,以一个全局单例模式管理。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex 的用法很简单, 一句话总结:commit mutation,dispatch action
参考链接:Vuex 官方文档
有限状态机(finite-state machine)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型,非常有用,可以模拟世界上大部分事物。
有限状态机并不是一个复杂的概念,简单说,它有三个特征:
使用状态去影响视图,而 Action 主要负责完成状态间的变更。代码如何更好的构建其核心在于使用最合理的状态去管理界面,并用最合理的动作去实现状态间的变更。
所谓的状态管理,实际上就是使用有限状态机来管理前端状态。
有限状态机对 JavaScript 的意义在于,很多对象可以写成有限状态机。
写代码之前,思考一下:
然后跟着思路,完成数据与 UI 部分。
参考链接:javascript-state-machine xstate managing-state-in-javascript-with-state-machines-stent
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。