Adblocker

mobx

Mobx

简单、可扩展的状态管理

安装

npm install mobx —save react绑定库: npm install mobx-react —save

observable & autorun

import { observable, autorun } from ‘mobx’; const value = observable(0); const number = observable(100); autorun(() => { console.log(value.get()); }); value.set(1); value.set(2); number.set(101);
控制台中一次输入 0,1,2
observable可以用来观测一个数据,这个数据可以是数字、字符串、数组、对象等类型,当观测到的数据发生变化的时候,如果变化的值处在autorun中,那么autorun就会自动执行。

计算属性—computed

假如现在我们一个数字,但我们对它的值不感兴趣,而只关心这个数组是否为正数。这个时候我们就可以用到computed这个属性了。
const number = observable(10); const plus = computed(() => number.get() > 0); autorun(() => { console.log(plus.get()); }); number.set(-19); number.set(-1); number.set(1);
依次输出了true,false,true
依次输出了true,false,true。
第一个true是number初始化值的时候,10>0为true没有问题。
第二个false将number改变为-19,输出false,也没有问题。
但是当-19改变为-1的时候,虽然number变了,但是number的改变实际上并没有改变plus的值,所以没有其它地方收到通知,因此也就并没有输出任何值。
直到number重新变为1时才输出true。

action,runInAction和严格模式(useStrict)

mobx推荐将修改被观测变量的行为放在action中。
import {observable, action} from ‘mobx’; class Store { @observable number = 0; @action add = () => { this.number++; } } const newStore = new Store(); newStore.add();
这个类中有一个add函数,用来将number的值加1,也就是修改了被观测的变量,根据规范,我们要在这里使用action来修饰这个add函数。

把@action去掉,程序还是可以运行
class Store { @observable number = 0; add = () => { this.number++; } }
这是因为现在我们使用的Mobx的非严格模式,如果在严格模式下,就会报错了。
接下来让我们来启用严格模式
import {observable, action, useStrict} from ‘mobx’; useStrict(true); class Store { @observable number = 0; @action add = () => { this.number++; } } const newStore = new Store(); newStore.add();
Mobx里启用严格模式的函数就是useStrict,注意和原生JS的”use strict”不是一个东西。
现在再去掉@action就会报错了。

action的写法大概有如下几种:

  • action(fn)
  • action(name, fn)
  • @action classMethod() {}
  • @action(name) classMethod () {}
  • @action boundClassMethod = (args) => { body }
  • @action(name) boundClassMethod = (args) => { body }
  • @action.bound classMethod() {}
  • @action.bound(function() {})

可以看到,action在修饰函数的同时,我们还可以给它设置一个name,这个name应该没有什么太大的作用,但可以作为一个注释更好地让其他人理解这个action的意图。

action只能影响正在运行的函数,而无法影响当前函数调用的异步操作
@action createRandomContact() { this.pendingRequestCount++; superagent .get(‘https://randomuser.me/api/‘) .set(‘Accept’, ‘application/json’) .end(action(“createRandomContact-callback”, (error, results) => { if (error) console.error(error); else { const data = JSON.parse(results.text).results[0]; const contact = new Contact(this, data.dob, data.name, data.login.username, data.picture); contact.addTag(‘random-user’); this.contacts.push(contact); this.pendingRequestCount—; } })); }
重点关注程序的第六行。在end中触发的回调函数,被action给包裹了,这就很好验证了上面加粗的那句话,action无法影响当前函数调用的异步操作,而这个回调毫无疑问是一个异步操作,所以必须再用一个action来包裹住它,这样程序才不会报错。。

如果你使用async function来处理业务,那么我们可以使用runInAction这个API来解决之前的问题。
import {observable, action, useStrict, runInAction} from ‘mobx’; useStrict(true); class Store { @observable name = ‘’; @action load = async () => { const data = await getData(); runInAction(() => { this.name = data.name; }); } }

runInAction有点类似action(fn)()的语法糖,调用后,这个action方法会立刻执行。

结合React使用

在React中,我们一般会把和页面相关的数据放到state中,在需要改变这些数据的时候,我们会去用setState这个方法来进行改变。
import React from ‘react’; import { observable, useStrict, action } from ‘mobx’; import { observer } from ‘mobx-react’; useStrict(true); class MyState { @observable num = 0; @action addNum = () => { this.num++; }; } const newState = new MyState(); @observer export default class App extends React.Component { render() { return (

{newState.num}

) } }

跨组件交互

在不使用其它框架、类库的情况下,React要实现跨组件交互这一功能相对有些繁琐。通常我们需要在父组件上定义一个state和一个修改该state的函数。然后把state和这个函数分别传到两个子组件里,在逻辑简单,且子组件很少的时候可能还好,但当业务复杂起来后,这么写就非常繁琐,且难以维护。而用Mobx就可以很好地解决这个问题。来看看以下的例子:
class MyState { @observable num1 = 0; @observable num2 = 100; @action addNum1 = () => { this.num1 ++; }; @action addNum2 = () => { this.num2 ++; }; @computed get total() { return this.num1 + this.num2; } } const newState = new MyState(); const AllNum = observer((props) =>

num1 + num2 = {props.store.total}
); const Main = observer((props) => (

num1 = {props.store.num1}

num2 = {props.store.num2}

)); @observer export default class App extends React.Component { render() { return (
); } }

网络请求

useStrict(true); class MyState { @observable data = null; @action initData = async() => { const data = await getData(“xxx”); runInAction(“说明一下这个action是干什么的。不写也可以”, () => { this.data = data; }) }; }
严格模式下,只能在action中修改数据,但是action只能影响到函数当前状态下的情景,也就是说在await之后发生的事情,这个action就修饰不到了,于是我们必须要使用了runInAction

装饰器报错

下载 npm install @babel/plugin-proposal-decorators
在 package.json 中修改babel:
“babel”: { “presets”: [ “react-app” ], “plugins”: [ [ “@babel/plugin-proposal-decorators”, { “legacy”: true } ] ] }

在 tsconfig.json 中修改:
{ “compilerOptions”: { “target”: “ES5”, “experimentalDecorators”: true } }
上一篇

dva

下一篇

hoc2