在美团实习的时候,第一次接触到dva这样的react框架,回学校的时候,就想有机会自己实现一下这样的框架,虽然自己水平有限,但是可以试一试哈。 目标是实现dva model的同步和异步 dispatch action。

看看 dva 的构成

let counterModel = {namespace: 'counter',state: {num: 0}reducers: {add(state, action){return {num: state.num   1} }}}

对state的更新

var app = new dva();
app.model(counterModel);
app.start();
app._store.dispatch({type: 'counter/add'
});

上述就是 dva 对 state 的更新, 通过dispatch {type: A / B} 其中 A 是指 model的 namespace, B 是指 model 中 reducers 具体的reducer方法。

其中 dva 对异步的处理是用 redux-saga 处理的,因为作者并不熟悉redux-saga,拿 redux-thunk 代替了。

好,我们开工了

  • 第一步 创建store

      const createStore = (reducer, initialState) => {let currentReducer = reducer;let currentState = initialState;let listener = () => { };return {getState() {return currentState;},dispatch(action) {let {type} = action;currentState = currentReducer(currentState, action);listener();return action;},subscribe(newListener) {listener = newListener;}}}
    

store 主要是 存储数据,开放state更新接口。

  • 第二步 引入中间件 applyMiddleware

     const compose = (...funcs) => {if (funcs.length === 0) {return arg => arg}if (funcs.length === 1) {return funcs[0]}const last = funcs[funcs.length - 1]const rest = funcs.slice(0, -1)return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));}const applyMiddleware = (...middlewares) => {return (createStore) => (reducer, initialState, enhancer) => {var store = createStore(reducer, initialState, enhancer)var dispatch = store.dispatch;var chain = [];var middlewareAPI = {getState: store.getState,dispatch: (action) => store.dispatch(action)}chain = middlewares.map(middleware => middleware(middlewareAPI))dispatch = compose(...chain)(store.dispatch)return {...store,dispatch}}}
    

redux 中间件 洋葱模型,修改了dispatch 方法。

  • 引入异步中间件redux-thunk和logger中间件

        const logger = store => next => action => {console.log('prevState', store.getState());let result = next(action);console.log('nextState', store.getState());return result;};const thunk = ({dispatch,getState}) => next => action => {if (typeof action === 'function') {return action(dispatch, getState);}return next(action);}
    

    这里引入 redux-thunk 做异步处理。

  • 加入测试model

      let counterModel = {namespace: 'counter',state: {num: 0},reducers: {add(state, action) {console.log('reducer add executed');return {num: state.num   1}},asyncAdd(state, action) {console.log('reducer asyncAdd executed');return {num: state.num   1}},test(state, action) {console.log('reducer test executed');return {state}}}};let userModel = {namespace: 'user',state: {name: 'xxxx'},reducers: {modify(state, {payload}) {console.log('reducer modify executed');let {name} = payloadreturn {name}}}};
    
  • 对不同model下的reducer进行分发

      const combineReducer = (reducers) => (state = {}, action) => {let {type} = action;let stateKey = type.split('/')[0];let reducer = type.split('/')[1];reducers.map((current) => {if (current.name === reducer) {state[stateKey] = current(state[stateKey], action);}});return state;}
    

    这里因为 combineReducer 是 reducer的总入口,在这里根据action 的 type 转发到具体model下的reducer方法

  • dva 构造函数

      class dva {constructor() {this._models = [];this._reducers = [];this._states = {};}model(model) {this._models.push(model);}start() {for (var i = 0; i < this._models.length; i  ) {this._states[this._models[i].namespace] = {...this._models[i].state};Object.keys(this._models[i].reducers).map((key) => {if (this._models[i].reducers.hasOwnProperty(key)) {this._reducers.push(this._models[i].reducers[key]);}})}var rootReducer = combineReducer(this._reducers);let createStoreWithMiddleware = applyMiddleware(thunk, logger)(createStore);this._store = createStoreWithMiddleware(rootReducer, this._states);this._store.subscribe(() => {console.log(this._store.getState());})}}
    

    dva 构造方法主要工作是缓存model,创建store。

测试数据

var app = new dva();
app.model(counterModel);
app.model(userModel);app.start();
app._store.dispatch({type: 'counter/add'
});app._store.dispatch({type: 'user/modify',payload: {name: 'shadow'}
})app._store.dispatch((dispatch, getState) => {setTimeout(() => {dispatch({type: 'counter/asyncAdd'})}, 5000);
})

控制台的输出


一点留言

这个当然是最粗糙的dva部分实现了,因为本身自己并没有去看dva源码,只是看了dva API 蒙头实现下,其中已经有很多很优秀的redux周边生态,例如redux-thunk,logger等。当然也是复习了一下部分redux源码了,当作自己学习的一个阶段学习吧,最后像dva作者 陈谦 致敬。

最后留个地址吧:

http://oymaq4uai.bkt.clouddn.com/index.js

更多专业前端知识,请上 【猿2048】www.mk2048.com

200行代码写一个简易的dva相关推荐

  1. C语言200行代码写一个贪吃蛇小游戏

    先看一眼主程序 一般小游戏的大致框架就是这个样子,这里主要分成画面的显示,与用户相关的更新,与用户无关的更新等三个部分.(完整代码附于文末) int main(int argc, char *argv ...

  2. 爬虫python代码-Python爬虫教程:200行代码实现一个滑动验证码

    Python爬虫教程:教你用200行代码实现一个滑动验证码 做网络爬虫的同学肯定见过各种各样的验证码,比较高级的有滑动.点选等样式,看起来好像挺复杂的,但实际上它们的核心原理还是还是很清晰的,本文章大 ...

  3. 前端 验证码隐藏怎么实现_Python爬虫教程:200行代码实现一个滑动验证码

    Python爬虫教程:教你用200行代码实现一个滑动验证码 做网络爬虫的同学肯定见过各种各样的验证码,比较高级的有滑动.点选等样式,看起来好像挺复杂的,但实际上它们的核心原理还是还是很清晰的,本文章大 ...

  4. python爬虫代码-Python爬虫教程:200行代码实现一个滑动验证码

    Python爬虫教程:教你用200行代码实现一个滑动验证码 做网络爬虫的同学肯定见过各种各样的验证码,比较高级的有滑动.点选等样式,看起来好像挺复杂的,但实际上它们的核心原理还是还是很清晰的,本文章大 ...

  5. SpringBoot,用200行代码完成一个一二级分布式缓存

    缓存系统的用来代替直接访问数据库,用来提升系统性能,减小数据库复杂.早期缓存跟系统在一个虚拟机里,这样内存访问,速度最快. 后来应用系统水平扩展,缓存作为一个独立系统存在,如redis,但是每次从缓存 ...

  6. [教你做小游戏] 用86行代码写一个联机五子棋WebSocket后端

    我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者HullQin授权.我独立开发了<联机桌游合集>,是个网页,可以很方便的跟朋友联机 ...

  7. 200行代码实现一个滑动验证码

    作者 | 崔庆才 转载自进击的Coder(ID: FightingCoder) 做网络爬虫的同学肯定见过各种各样的验证码,比较高级的有滑动.点选等样式,看起来好像挺复杂的,但实际上它们的核心原理还是还 ...

  8. PONG - 100行代码写一个弹球游戏

    大家好,欢迎来到 Crossin的编程教室 ! 今天跟大家讲一讲:如何做游戏 游戏的主题是弹球游戏<PONG>,它是史上第一款街机游戏.因此选它作为我这个游戏开发系列的第一期主题. 游戏引 ...

  9. 100行代码写一个Compose版华容道

    之前写过几个 Compose 的 demo,但一直没使用到 Gesture, Theme 等特性,于是写了一个华容道的小程序来展示上述这些特性.写完后又一次被 Compose 的生产力所折服,整个程序 ...

最新文章

  1. MVC控件类型-HtmlHelper类
  2. Snmp在Windows下的实现----WinSNMP编程原理
  3. (0059)iOS开发之添加自定义字体库并设置文本字体
  4. Tom's Classes
  5. python类继承的重写和super
  6. java 加密解密简单实现
  7. java解析dxf文件_浅析JVM方法解析、创建和链接
  8. mysql数据库备份工具expdb_expdp 备份数据库
  9. MTK中断控制器简单记录
  10. 投影仪融合+拼接处理系统制作原理
  11. BERTILO发“富”啦,来元代艺数get你的专属「招财兔」!
  12. Gos —— 启动分页机制
  13. HP小型机系统管理员必读
  14. 没有软件开发人员,可以办理CMMI3级吗?
  15. 什么是量子霸权?我们如何才能实现它?
  16. Paper reading (四十四): Machine learning methods for metabolic pathway prediction
  17. android仿喜马拉雅APP状态栏,源码分享:高仿喜马拉雅FM
  18. 使用Webcam完成拍照功能
  19. astrolog php,Astrolog星象学软件使用指南(2)
  20. JS---如何避免用户在请求时“猛击”

热门文章

  1. android webview javascript不执行,WebView中的JavaScript为什么不执行?
  2. python怎么使用预训练的模型_Keras使用ImageNet上预训练的模型方式
  3. python框架源码学习
  4. Mac os下android studio模拟器无法联网解决方法
  5. 由于html元素加载导致的问题
  6. cookie 和session 的区别
  7. 【转】IP Socket知识
  8. vue进入页面执行的钩子函数_解决VUE mounted 钩子函数执行时 img 未加载导致页面布局的问题...
  9. C++设计模式——单例模式
  10. Lintcode--6(767)--翻转数组