当前位置: 首页 > 科技观察

说说MobX入门指南

时间:2023-03-18 17:54:18 科技观察

之前用了很多Redux,一直听说Mobx可以让你体验在React中写Vue的感觉。今天打算试试Mobx,看看是不是真的有写Vue的感觉。题外话在介绍MobX的用法之前,先说一些题外话。我们可以看看MobX的中文介绍。MobX的中文官网上说:“MobX是一个经过战争洗礼的库,通过透明的函数式响应式编程让状态管理变得简单和可扩展。数据流“经过战争洗礼的图书馆”感觉很奇怪,读起来很费口舌??,网上很多介绍MobX的文章都是这样写的。我在github上看了它的README,发现里面写着:“MobXisabattletestedlibrarythatmakesstatemanagementsimpleandscalablebytransparentlyapplyingfunctionalreactiveprogramming(TFRP)).可见作者的本意是MobX通过了很多测试,具有比较强的健壮性。以下是谷歌翻译的结果,似乎比中文网站上的表达更准确。虽然谷歌翻译,我的英文水平也很好,还是尽量阅读官方文档,以免造成一些不必要的误会。如何使用?言归正传,最新版本的MobX是6.0。与之前的版本相比,API得到了极大的简化,可以说是更加易用了。之前的版本是装饰器式的语法糖,但是装饰器在现在的ES规范中并不成熟,装饰器语法的引入也在增加打包代码的体积。经过综合考虑,MobX6.0取消了装饰器语法的API。响应式对象MobX使用makeObservable方法构造响应式对象。传入的对象属性会通过Proxy代理,类似于Vue。在6.0版本之前,使用的是Object.definePropertyAPI。当然6.0也提供了降级方案。import{configure,makeObservable,observable,action,computed}from'mobx'//使用这个配置,Proxy可以降级为Object.definePropertyconfigure({useProxies:"never"});//构造响应对象conststore=makeObservable(//需要代理的响应对象{count:0,getdouble(){returnthis.count*2},increment(){this.count+=1},decrement(){this.count-=1}},//对每个Attribute包装,用来标记属性的作用{count:observable,//需要跟踪的response属性double:computed,//Computed属性increment:action,//action调用后,responseobject会被修改decrement:action,//action被调用后,responseobject会被修改})我们看的是之前版本的MobX,使用了装饰器:classStore{@observablecount=0constructor(){makeObservable(this)}@actionincrement(){this.count++;}@actiondecrement(){this.count--;}@computedgetdouble(){returnthis.count*2}}conststore=newStore()似乎writing方法并没有简化,看起来比写装饰器还要复杂。我们来看看6.0版本中一个更强大的API:makeAutoObservable。makeAutoObservable是一个更强大的makeObservable,可以自动为属性添加对象包装函数,上手成本直线下降。import{makeAutoObservable}from'mobx'conststore=makeAutoObservable({count:0,getdouble(){returnthis.count*2},increment(){this.count+=1},decrement(){this.count-=1}})ComputedpropertyMobX的property和Vue的computed是一样的。它是makeAutoObservable中的一个getter。一旦getter依赖的值发生变化,getter本身的返回值也会发生变化。import{makeAutoObservable}from'mobx'conststore=makeAutoObservable({count:0,getdouble(){returnthis.count*2}})当store.count为1时,调用store.double会返回2。修改行为当我们需要修改store上的response属性,我们可以通过直接重新赋值来修改它,但是这样会得到MobX的警告??。conststore=makeAutoObservable({count:0});document.getElementById("increment").onclick=function(){store.count+=1}warnMobX会提示修改响应对象的属性时,需要使用动作方法修改。虽然直接修改也可以生效,但是这会让MobX状态的管理更加混乱,而把状态修改放到action中可以让MobX在内部交易过程中修改,不至于获取到一个仍然是的属性在中间状态,最终的计算结果不够准确。makeAutoObservable中的所有方法都会被处理成动作。import{makeAutoObservable}from'mobx'conststore=makeAutoObservable({count:0,getdouble(){returnthis.count*2},increment(){//actionthis.count+=1},decrement(){//actionthis.count-=1}})与Vuex不同,Vuex将状态修改分为mutation和action,同步修改放在mutation,异步操作放在action。在MobX中,无论是同步操作还是异步操作,都可以放在action中,但是异步操作修改属性时,赋值操作需要放在runInAction中。import{runInAction,makeAutoObservable}from'mobx'conststore=makeAutoObservable({count:0,asyncinitCount(){//模拟远程数据获取constcount=awaitnewPromise((resolve)=>{setTimeout(()=>{resolve(10)},500)})//拿到数据后,把赋值操作放在runInAction中调用一个已经存在的action。import{runInAction,makeAutoObservable}from'mobx'conststore=makeAutoObservable({count:0,setCount(count){this.count=count},asyncinitCount(){//模拟获取远程数据constcount=awaitnewPromise((resolve)=>{setTimeout(()=>{resolve(10)},500)})//获取到数据后,调用已有的actionthis.setCount(count)}})store.initCount()来监听对象变化无论是在React还是如果要在小程序中引入MobX,需要在对象发生变化时调用原生的setState/setData方法,将状态同步到视图。这个能力可以通过autorun方法实现,我们可以理解为ReactHooks中的useEffect。每次修改store的response属性时,都会调用传入autorun的方法(effect)。import{autorun,makeAutoObservable}from'mobx'conststore=makeAutoObservable({count:0,setCount(count){this.count=count},increment(){this.count++},decrement(){this.count--}})document.getElementById("increment").onclick=function(){store.count++}const$count=document.getElementById("count")$count.innerText=`${store.count}`autorun(()=>{$count.innerText=`${store.count}`})每当点击button#increment按钮时,span#count中的值会自动同步。??查看完整代码。效果演示除了autorun,MobX还提供了更精细化的监控方式:reaction,when。conststore=makeAutoObservable({count:0,setCount(count){this.count=count},increment(){this.count++},decrement(){this.count--}})//store修改立即调用effectautorun(()=>{$count.innerText=`${store.count}`});//修改第一个方法的返回值后,会调用后续的effectReaction(//表示store.count会只被修改call()=>store.count,//第一个参数为当前值,第二个参数为修改前的值//有点类似于watch(value,prevValue)=>{console.log('diff',value-prevValue)});//第一个方法的返回值为true,立即调用下面的效果when(()=>store.count>10,()=>{console.log(store.count)})//when方法也可以返回一个promise(asyncfunction(){awaitwhen(()=>store.count>10)console.log('store.count>10')})()总结了MobX的引入这是这里的尽头。本文只简单罗列了MobX的API。希望你能有所收获。以后打算深入研究MobX的实现。等我研究完了,我会写一篇文章来分享。