【MobX】391- MobX 入门教程(下)
三、MobX 常用 API 介绍
3. 修改可观察数据
在上一部分内容中,我们了解到,对可观察的数据做出反应的时候,需要我们手动修改可观察数据的值。这种修改是通过直接向变量赋值来实现的,虽然简单易懂,但是这样会带来一个较为严重的副作用,就是每次的修改都会触发 autorun 或者 reaction 运行一次。多数情况下,这种高频的触发是完全没有必要的。
比如用户对视图的一次点击操作需要很多修改 N 个状态变量,但是视图的更新只需要一次就够了。
为了优化这个问题, MobX 引入了 action 。
3.1 (@)action
action 是修改任何状态的行为,使用 action 的好处是能将多次修改可观察状态合并成一次,从而减少触发 autorun 或者 reaction 的次数。
可以理解成批量操作,即一次动作中包含多次修改可观察状态,此时只会在动作结束后,做一次性重新计算和反应。
action 也有两种使用方法,这里以 decorate 方式来介绍。
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.string 和 store.number 两个变量后,再运行 store.bar() 会发现,控制台值输出一次 ["pingan", 100] ,这就说明 reaction 只被执行一次。
知识点:action.bound
另外 action 还有一种特殊使用方法:action.bound,常常用来作为一个 callback 的方法参数,并且执行效果也是一样:
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)() 的语法糖。
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 简单实例
这里以简单计数器为例,实现点击按钮,数值累加的简单操作,如图:
在这个案例中,我们引用 mobx-react 库来实现,很明显可以看出 mobx-react 是作为 mobx 和 react 之前的桥梁。
它将 react 组件转化为对可观察数据的反应,也就是将组件的 render 方法包装成 autorun 方法,使得状态变化时能自动重新渲染。
详细可以查看:https://www.npmjs.com/package/mobx-react 。
接下来开始我们的案例:
1. 安装依赖和配置webpack
由于配置和前面第二节介绍差不多,所以这里会以第二节的配置为基础,添加配置。
首先安装 mobx-react 依赖:
cnpm i mobx-react -D
修改webpack.config.js,在 presets 配置中添加 react 进来:
// ... 省略其他
- 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 项目
这里初始化一下我们本次项目的简单骨架:
// 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"))
这些组件对应到我们最后页面效果如图:
2. 实现 Store 类
Store 类用于存储数据。
class Store {
@observable cache = { queue: [] }
@action.bound refresh(){
this.cache.queue.push(1)
}
}
3. 实现 Bar 和 Foo 组件
实现代码如下:
@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>
}
}
这里需要注意:
可观察数据类型中的数组,实际上并不是数组类型,这里需要用
observablePropTypes.observableArray去声明它的类型,对象也是一样。@observer在需要根据数据变换,而改变UI的组件去引用,另外建议有使用到相关数据的类都引用。事实上,我们只需要记住
observer方法,将所有React组件用observer修饰,就是react-mobx的用法。
4. 使用 Foo 组件
最后我们使用 Foo 组件,需要给它传递两个参数,这样 Bar 组件才能拿到并使用:
ReactDOM.render(
<Foo cache={store.cache}
refresh={store.refresh}
/>,
document.querySelector("#root")
)
结尾
本文参考:
- 《MobX 官方文档》
- 茵风泳月《MobX 入门基础教程》
【MobX】391- MobX 入门教程(下)的更多相关文章
- 【MobX】390- MobX 入门教程(上)
点击上方"前端自习课"关注,学习起来~ 本文考虑到篇幅问题,将<MobX 入门教程>分成上.下两篇文章,方便阅读.分配安排: 一.MobX 介绍 首先看下官网介绍: ★ ...
- django入门教程(下)
在两篇文章帮你入门Django(上)一文中,我们已经做了一个简单的小网站,实现了保存用户数据到数据库,以及从后台数据库读取数据显示到网页上这两个功能. 看上去没有什么问题了,不过我们可以让它变得更加完 ...
- jenkins 入门教程(下)
接上回继续学习jenkins,这次主要来看一些疑难杂症: 一.yum install安装方式 除了直接java -jar jenkins.war方式,还可以用yum安装,这种方式下提供了更多的可配置选 ...
- Odoo进销存(采购、销售、仓库)入门教程 - 下
转帖地址:http://blog.csdn.net/wangnan537/article/details/46475105 2. 进销存实务 2.1 销售产品 李逍遥接到客户苏州美尚邻里超市购买10只 ...
- Spring Boot入门教程1、使用Spring Boot构建第一个Web应用程序
一.前言 什么是Spring Boot?Spring Boot就是一个让你使用Spring构建应用时减少配置的一个框架.约定优于配置,一定程度上提高了开发效率.https://zhuanlan.zhi ...
- Spring Boot入门教程2-1、使用Spring Boot+MyBatis访问数据库(CURD)注解版
一.前言 什么是MyBatis?MyBatis是目前Java平台最为流行的ORM框架https://baike.baidu.com/item/MyBatis/2824918 本篇开发环境1.操作系统: ...
- Spring Cloud 入门教程(四): 分布式环境下自动发现配置服务
前一章, 我们的Hello world应用服务,通过配置服务器Config Server获取到了我们配置的hello信息“hello world”. 但自己的配置文件中必须配置config serve ...
- Unity入门教程(下)
一.概要 在 Unity入门教程(上) 中我们创建了一个游戏项目,并且创建了玩家角色和小球这些游戏对象,还通过添加游戏脚本实现了小方块的弹跳.虽然功能比较简单,但是完整地表现了使用Unity开发游戏的 ...
- Arduino可穿戴开发入门教程Windows平台下安装Arduino IDE
Arduino可穿戴开发入门教程Windows平台下安装Arduino IDE Windows平台下安装Arduino IDE Windows操作系统下可以使用安装向导和压缩包形式安装.下面详细讲解这 ...
随机推荐
- Windows下搭建远程Linux主机的图形化本地开发环境
在实际开发中,项目的类生产.生产环境一般都是选择Linux为服务器进行部署. 相应的,我们的开发最好也在Linux环境下进行,否则容易引发其他的问题,比如不同环境下功能不一致.库依赖差异等. 但是Li ...
- PHP字符逃逸导致的对象注入
1.漏洞产生原因: 序列化的字符串在经过过滤函数不正确的处理而导致对象注入,目前看到都是因为过滤函数放在了serialize函数之后,要是放在序列化之前应该就不会产生这个问题 ?php functio ...
- Project Euler 63: Powerful digit counts
五位数\(16807=7^5\)也是一个五次幂,同样的,九位数\(134217728=8^9\)也是一个九次幂.求有多少个\(n\)位正整数同时也是\(n\)次幂? 分析:设题目要求的幂的底为\(n\ ...
- drf序列化组件之视图家族
一.视图家族的分类 1.导入分类 from rest_framewok import views, generics, mixins, viewsets views:视图类 两大视图类:APIVi ...
- vim用户手册笔记常用操作整理
"x"命令可以删除一个字符 "d"命令可以后跟任何一个位移命令,它将删除从当前光标起到位移的终点处的文本内容dw "c",改变命令例如cw ...
- Flex实现web版图片查看器
项目需求: 在web端实现图片浏览,具有放大.缩小.滚轴放大缩小.移动.旋转以及范围控制. 成果图:
- Flutter学习笔记(30)--Android原生与Flutter混编
如需转载,请注明出处:Flutter学习笔记(30)--Android原生与Flutter混编 这篇文章旨在学习如何在现有的Android原生项目上集成Flutter,实现Android与Flutte ...
- sublimetext使用教程
图片来自网络,仅供参考 前言 随着我们编写的代码越来越复杂,DevC++以不再能满足我们的需求,所以,我们需要 一个能够进行调试,编译,运行等等功能的现代化ide,sublimetext(以下简称ST ...
- Leetcode 1020 飞地的数量
地址 https://leetcode-cn.com/problems/number-of-enclaves/ 给出一个二维数组 A,每个单元格为 0(代表海)或 1(代表陆地). 移动是指在陆地上从 ...
- Java8 Stream终端操作使用详解
话不多说,自己挖的坑自己要填完,今天就给大家讲完Java8中Stream的终端操作使用详解.Stream流的终端操作主要有以下几种,我们来一一讲解. forEach() forEachOrdered( ...