【MobX】391- MobX 入门教程(下)

2019-10-30 11:31:41 浏览数 (1)

三、MobX 常用 API 介绍

3. 修改可观察数据

在上一部分内容中,我们了解到,对可观察的数据做出反应的时候,需要我们手动修改可观察数据的值。这种修改是通过直接向变量赋值来实现的,虽然简单易懂,但是这样会带来一个较为严重的副作用,就是每次的修改都会触发 autorun 或者 reaction 运行一次。多数情况下,这种高频的触发是完全没有必要的。

比如用户对视图的一次点击操作需要很多修改 N 个状态变量,但是视图的更新只需要一次就够了。

为了优化这个问题, MobX 引入了 action

3.1 (@)action

action 是修改任何状态的行为,使用 action 的好处是能将多次修改可观察状态合并成一次,从而减少触发 autorun 或者 reaction 的次数。

可以理解成批量操作,即一次动作中包含多次修改可观察状态,此时只会在动作结束后,做一次性重新计算和反应。

action 也有两种使用方法,这里以 decorate 方式来介绍。

代码语言:javascript复制
import { observable, computed, reaction, action} from 'mobx'

class Store {
    @observable string = 'leo';
    @observable number = 123;
    @action bar(){
        this.string = 'pingan'
        this.number = 100
    }
}
let store = new Store()
reaction(() => [store.string, store.number], arr => {
    console.log(arr)
})
store.bar() // ["pingan", 100]

当我们连续去修改 store.stringstore.number 两个变量后,再运行 store.bar() 会发现,控制台值输出一次 ["pingan", 100] ,这就说明 reaction 只被执行一次。

知识点:action.bound

另外 action 还有一种特殊使用方法:action.bound,常常用来作为一个 callback 的方法参数,并且执行效果也是一样:

代码语言:javascript复制
import { observable, computed, reaction, action} from 'mobx'

class Store {
    @observable string = 'leo';
    @observable number = 123;
    @action.bound bar(){
        this.string = 'pingan'
        this.number = 100
    }
}
let store = new Store()
reaction(() => [store.string, store.number], arr => {
    console.log(arr)
})
let bar = store.bar;
function foo(fun){
    fun()
}
foo(bar) //["pingan", 100]
知识点:runInAction(name?, thunk)

runInAction 是个简单的工具函数,它接收代码块并在(异步的)动作中执行。这对于即时创建和执行动作非常有用,例如在异步过程中。runInAction(f)action(f)() 的语法糖。

代码语言:javascript复制
import { observable, computed, reaction, action} from 'mobx'
class Store {
    @observable string = 'leo';
    @observable number = 123;
    @action.bound bar(){
        this.string = 'pingan'
        this.number = 100
    }
}
let store = new Store()
reaction(() => [store.string, store.number], arr => {
    console.log(arr)
})
runInAction(() => {
    store.string = 'pingan'
    store.number = 100
})//["pingan", 100]

四、 Mobx-React 简单实例

这里以简单计数器为例,实现点击按钮,数值累加的简单操作,如图:

2019102301.png

在这个案例中,我们引用 mobx-react 库来实现,很明显可以看出 mobx-react 是作为 mobxreact 之前的桥梁。

它将 react 组件转化为对可观察数据的反应,也就是将组件的 render 方法包装成 autorun 方法,使得状态变化时能自动重新渲染。

详细可以查看:https://www.npmjs.com/package/mobx-react 。

接下来开始我们的案例:

1. 安装依赖和配置webpack

由于配置和前面第二节介绍差不多,所以这里会以第二节的配置为基础,添加配置。

首先安装 mobx-react 依赖:

代码语言:javascript复制
cnpm i mobx-react -D

修改webpack.config.js,在 presets 配置中添加 react 进来:

代码语言:javascript复制
// ... 省略其他
- entry: path.resolve(__dirname, 'src/index.js'),
  entry: path.resolve(__dirname, 'src/index.jsx'),
module: {
    rules: [{
        test: /.jsx?$/,
        exclude: /node_modules/,
        use: {
            loader: 'babel-loader',
            options: {
-                 presets: ['env'],
                  presets: ['env', 'react'],
                plugins: ['transform-decorators-legacy', 'transform-class-properties']
            }
        }
    }]
},

2. 初始化 React 项目

这里初始化一下我们本次项目的简单骨架:

代码语言:javascript复制
// index.jsx
import { observable, action} from 'mobx';
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {observer, PropTypes as observablePropTypes} from 'mobx-react'

class Store {
}
const store = new Store();
class Bar extends Component{
}
class Foo extends Component{
}
ReactDOM.render(<Foo />, document.querySelector("#root"))

这些组件对应到我们最后页面效果如图:

2019102302.png

2. 实现 Store 类

Store 类用于存储数据。

代码语言:javascript复制
class Store {
    @observable cache = { queue: [] }
    @action.bound refresh(){
        this.cache.queue.push(1)
    }
}

3. 实现 Bar 和 Foo 组件

实现代码如下:

代码语言:javascript复制
@observer
class Bar extends Component{
    static propTypes = {
        queue: observablePropTypes.observableArray
    }
    render(){
        const queue = this.props.queue;
        return <span>{queue.length}</span>
    }
}

class Foo extends Component{
    static propTypes = {
        cache: observablePropTypes.observableObject
    }
    render(){
        const cache = this.props.cache;
        return <div>
          <button onClick={this.props.refresh}>点击   1</button> 
        当前数值:<Bar queue={cache.queue} />
        </div>
    }
}

这里需要注意:

  1. 可观察数据类型中的数组,实际上并不是数组类型,这里需要用 observablePropTypes.observableArray 去声明它的类型,对象也是一样。
  2. @observer 在需要根据数据变换,而改变UI的组件去引用,另外建议有使用到相关数据的类都引用。
  3. 事实上,我们只需要记住 observer 方法,将所有 React 组件用 observer 修饰,就是 react-mobx 的用法。

4. 使用 Foo 组件

最后我们使用 Foo 组件,需要给它传递两个参数,这样 Bar 组件才能拿到并使用:

代码语言:javascript复制
ReactDOM.render(
  <Foo cache={store.cache} 
    refresh={store.refresh}
  />,
  document.querySelector("#root")
)

结尾

本文参考:

  • 《MobX 官方文档》
  • 茵风泳月《MobX 入门基础教程》

0 人点赞