简化React中的Action的写法,不要中间件,不写dispatch


声明:本文转载自https://my.oschina.net/evolify/blog/1615769,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

  我们在写React应用时,通常用到redux做状态管理,然后会用到一些中间件来支持异步action,比如redux-thunk.通常我们的代码类似下面这样的:

//ActionType  R.js export ActionType{   	TYPE1:'type1',     	TYPE2:'type2',       TYPE3:'type3',       // others }      //reducer reducer.js import {ActionType as AT} from 'R' export default function(state={},action){   switch(action.type){     case AT.TYPE1:       	return {           ...state,           ...action.data,           // or other         }     case AT.TYPE2:           //...     default:     	return state         }       }  //Action Action.js import {ActionType as AT} from 'R' const act = {   action1:data=>dispatch=>{     // some action such as ajax     dispatch({       type:AT.TYPE1,       data:{         // data       }     })   }       action2:()=>(dispatch,getState)=>{   	// call another action   	dispatch(act.action3())   }   action3:()=>()=>{     // even you never use the dispath or getState,you still have to code like this.   } } export default act  // Component @connect( 	state=>state.reducer1,   	dispatch=>bindActionCreators(Action,dispatch) ) export default class View extends React.Component{          doAction1(){       this.props.action1({})     }          render(){       return(       	<div>           anything else         </div>       )     } } 

  功能很简单,却需要些这么多actionType, reducer里面还有那么多case分支。而最烦的是action,直觉上我们是希望能够写普通的function,而不用强行写上dispatch和getState, 一个action调用另一个action竟然也不能直接调用。虽然我们知道是需要这样做,需要用actionType来区分action,reducer里面也需要根据type来做相应的更新,action中也需要dispatch来发出action。

  但如果我们就是不想写的这么麻烦,能有什么办法吗?

  答案之一是用mobx之类的工具来管理状态。当然,本文要介绍的是在redux中的方法,ev-redux. 先来看看使用后的效果:

  首先安装:npm i --save ev-redux

  然后你的代码差不多是这样:

// init evStore in you app.js when create store. import {evStore} from 'easy-redux' const store = createStore(...) evStore.init(store)  // redux/reducer.js import {ActionType as TYPE} from './index.js' const initState={} export default function(state=initState,action){     if(action.type === TYPE){         return {             ...state,             ...action.data         }     }     return state }  // redux/Action.js import {evRedux} from 'ev-redux'  @evRedux export default class Action{     constructor(actionType){         this.actionType = actionType     }     action1(x){         this.update({             x         })     }     action2(){         this.dispatch({             type:this.actionType,             data:{y:this.getState().reducer2.y+1}         })       	// to call another action, just call no need dispath!       	this.action3({z:3})         // or just update         // this.update({y:this.getState().reducer2.y+1})     }     action3(z){         setTimeout(()=>{             this.update({z})         },1000)     } }  // redux/index.js import Action from './Action' import reducer from './reducer' import {connect as conn} from 'react-redux'  const connect = view => conn(state=>state.reducer2)(view) const ActionType = Symbol() const action = new Action(ActionType)  export {reducer,ActionType,action,connect}  // Component import action from './action' @connect export default class View extends React.Component{          doAction1(){       // just call an action as we call a function.       action.action1()     }          render(){       return(       	<div>           anything else         </div>       )     } } 

  不要只看着代码并没有减少。仔细看看 reducer和action部分,这样的action,这样的reducer你还不愿意用嘛?

  • 不需要中间件来支持异步任务。
  • 不需要去写那么多actionTypes,一个reducer对应一个action就行,使用symbol保证不重复。
  • reducer中不需要那么多case分支,只需要合并一下action传过来的state和原来的state就可以。
  • 重点是action,不需要手动在每个方法上加上dispatch和getState.你只需要在需要更新store时,构造好需要更新的那部分state,,然后调用update就行,type都不需要带。update哪儿来的?你直接用就行,后面会说。如果你想要用dispath和getState,直接从上下文取就行,this.dispatch,this.getState随便用。调用其他action,直接用this调用就ok,就像调用普通方法那样调用。

ok了,用法介绍完了。具体的原理简单说明一下:

  首先我们要触发reducer来更新store,就要用到dispatch来分发action。我们的update方法里面就是这么做的。之所以把构造要更新的state方法action, 而不是在reducer中通过不同的type来区分,是因为我觉得对于每个action,里需要更新那部分state,在action里面你是最清楚的。如果你在actino里面只是dispatch一个action,然后去reducer中构造state结构并更新,你不仅要写很多个多余的actionType,而且可能还要回头看这个type是哪个action触发的,还要回想这个action里面传过来的data是什么样的,明显比在action中构造要复杂。

  至于为什么action中我们明明没写update,却可以直接用,其实在easy-redux中,我们对action做了代理。在初始或easyStore时,我们能够获取到dispatch和getState,然后在action的get方法中,我们用反射来set update、dispatch、getState. 这样在我们的action中就能够直接在上下文中调用到它们了。

  原理就是用到js里面的代理和反射,代码也很简单,这里就不展开说明了,直接放上github地址:https://github.com/evolify/EvRedux

本文发表于2018年01月30日 22:31
(c)注:本文转载自https://my.oschina.net/evolify/blog/1615769,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1801 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1