200行代码写一个简易的dva
在美團實習的時候,第一次接觸到dva這樣的react框架,回學校的時候,就想有機會自己實現(xiàn)一下這樣的框架,雖然自己水平有限,但是可以試一試哈。 目標是實現(xiàn)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 代替了。
好,我們開工了
-
第一步 創(chuàng)建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 主要是 存儲數(shù)據,開放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進行分發(fā)
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 轉發(fā)到具體model下的reducer方法
-
dva 構造函數(shù)
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,創(chuàng)建store。
測試數(shù)據
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部分實現(xiàn)了,因為本身自己并沒有去看dva源碼,只是看了dva API 蒙頭實現(xiàn)下,其中已經有很多很優(yōu)秀的redux周邊生態(tài),例如redux-thunk,logger等。當然也是復習了一下部分redux源碼了,當作自己學習的一個階段學習吧,最后像dva作者 陳謙 致敬。
最后留個地址吧:
http://oymaq4uai.bkt.clouddn.com/index.js
更多專業(yè)前端知識,請上 【猿2048】www.mk2048.com
總結
以上是生活随笔為你收集整理的200行代码写一个简易的dva的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ulli*3 实现翻书动画效果
- 下一篇: 前端通过spark-md5.js计算本地