以前写过一篇 Regular 组件开发的一些建议 的文章提到了平常开发Regular组件的一些槽点,并提出了在简单需求,不使用状态管理框架时的一些替代方案。本文的目的即是填前文的一个坑,即较复杂需求下 Redux 引入方案。
html
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。前端
const store = redux.createStore(function(prevState, action) {
if (!prevState) {
prevState = {
count: 0
};
}
switch(action.type) {
case 'REQUEST':
return {
count: prevState.count + 1
}
}
return prevState;
});
store.dispatch({
type: 'REQUEST'
});
store.subscribe(function () {
console.log(store.getState());
});
复制代码
理解他,咱们能够结合后端 MVC 的 web 模型git
const store = redux.createStore(f);
复制代码
createStore 这个 API 会建立一台应用服务器,包含数据库存储,以及一个 web Servergithub
const state = store.getState()
复制代码
getState 操做会返回当前的服务器数据库数据,这台数据库 bind 了 0.0.0.0(闭包),因此外界没法操做关于数据库的信息,只能经过内部的服务对数据库作修改web
store.dispatch({
type: 'type',
payload: {}
})
复制代码
dispatch(action) 的操做就像是往服务器发送请求。action.type 就像是请求的 uri,action.payload 就像是请求的 body/query。数据库
const reducer = function (prevState, action) {
if (!prevState) {
return {}
}
switch(action.type) {
// 分发处理
}
return prevState;
}
redux.createStore(reducer);
复制代码
相应请求会进入对应的控制器(就像 reducer 的 switch 判断),而控制器内也会对请求携带的信息(payload)作分析,来实现对数据库的增删改查。redux
整个应用的 state 被储存在一棵 object tree 中,而且这个 object tree 只存在于惟一一个 store 中。小程序
通常状况下 createStore 建立的 store ,将做用于整个应用后端
惟一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。微信小程序
避免人为的操做 state 变量,形成状态变化不可预测的状况,人为修改 state 的方式被切断了。
至于如何实现,点我看源码
createStore
的操做,会建立一个内部变量 state, 因为 return 出来的 dispatch
和 subscribe
方法保持了对 state 变量的引用,因此 state 会以闭包的形式存活下来。
为了描述 action 如何改变 state tree ,你须要编写 reducers。
使用纯函数,可测试性和可维护性获得了保障。
Redux 职责是状态管理,并不是只限定于前端开发,要使用到 web 开发当中,还缺乏一个部分,完成 MVC 中剩下的一些操做(渲染页面)。
const store = redux.createStore(reducer);
const ComponentA = Regular.extend({
config() {
const ctx = this;
store.subscribe(function () {
const state = store.getState();
const mapData = {
clicked: state.clicked,
}
Object.assign(ctx.data, mapData);
ctx.$update();
});
}
});
复制代码
<StoreProvier store={store}>
<Component></Component>
</StoreProvier>
复制代码
const Component = connect({
mapState(state) {
return {
clicked: state.clicked,
}
}
})(Regular.extend({
config() {
}
}))
复制代码
Regular.extend({
name: 'StoreProvider',
template: '{#include this.$body}',
config({store} = this.data) {
if (!store) {
throw new Error('Provider expected data.store to be store instance created by redux.createStore()')
}
store.subscribe(() => {
this.$update();
});
}
})
复制代码
统一从最外层的 StoreProvider 组件获取 store,保证单一数据源
function getStore(ctx) {
let parent = ctx.$parent;
while(true) {
if (!parent) {
throw new Error('Expected root Component be Provider!')
}
if (parent.data.store) {
return parent.data.store;
}
parent = parent.$parent;
}
}
function connect({
mapState = () => ({}),
dispatch
} = {}) {
return (Component) => Component.implement({
events: {
$config(data = this.data) {
const store = getStore(this);
const mapStateFn = () => {
const state = store.getState();
const mappedData = mapState.call(this, state);
mappedData && Object.assign(this.data, mappedData);
}
mapStateFn();
const unSubscribe = store.subscribe(mapStateFn);
if (dispatch) {
this.$dispatch = store.dispatch;
}
this.$on('destroy', unSubscribe);
}
}
});
}
复制代码
至此回过头看 regualr-redux 的架构图,发现正是 StoreProvier
和 connect
操做帮助 redux
完成了与 MVC 相差的更新视图操做。
借助 redux 与特定框架的链接器,咱们会发现,对特定 MVVM 框架的要求会变得很低 -- mapState 操做能够完成 相似 Vue 中 computed/filter 的操做。
因此,现在还在半残废中的微信小程序也很适合基于这套思路来结合 redux (逃)。
带来的好处是,你能够安心维护你的模型层,不用担忧 data
过大致使的脏值检查缓慢,也不须要考虑一些逻辑相关的数据不放入 data
那该放入何处。
相信阅读此文,你会对 Redux
解决问题的方式有了必定的认识,而继续深刻的一些方向有:
* middleway 实现原理,redux-logger 和 redux-thunk 等实现方案;
* State 范式化;
* Presentational and Container Components
* 单页的 redux 架构设计
全文完 ;)
by 君羽
PS:戳我查看原文