0%

mobx学习笔记

安装

npm install mobx --save

配合React: npm install mobx-react --save

概述

MobX 是一个通过对开发者透明的函数响应式编程(TFRP)方式,让状态管理(state management)变得简单、具有高扩展性的库,并且这个库经过了严格的测试。

MobX的思想非常简单:来源于应用的状态的任何事物,都能被自动获得。

包括UI、数据变更、与服务器通信等等。

核心概念

可观察的状态(observable state)

MobX 给已有的数据结构增加了可观察的能力(如对象、数组、类实例等)。你只需要很简单地使用@observable 装饰你的类属性(property)即可。

1
2
3
4
5
class Todo {
id = Math.random();
@observable title = "";
@observable finished = false;
}

计算值(Computed values)

使用 MobX,你可以很容易的定义计算值,当相关数据变化时,计算值会自动发生变化。 计算值可以通过使用 @computed 装饰器声明,也可以通过 (extend)Observable 配合 getter/setter 函数进行声明。

1
2
3
4
5
6
class TodoList {
@observable todos = [];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}

MobX 会确保当一个 todo 增加或者当 finished 改变时, unfinishedTodoCount 是自动更新的。 计算值类似于电子表格程序的公式。它们的更新永远是自动的,并且只在需要的时候更新。

@observer

observer 函数/装饰器可以用来将 React 组件转变成响应式组件。当被监听的变量更改的时候,引用到该变量的组件会相应重新渲染。

当组件之间有嵌套情况的时候,向子组件传递的是引用,而不是该引用的值。

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就是用来修饰改变观察值的函数。

mobx还有很多其他的函数以及方法,这里只介绍了其中最常用的四个,其他的功能可以在 mobx官网 中查看。

应用

下面是一个简单的mobx应用,一个父组件包含着两个子组件。当其中一个子组件发生改变时,不会触发另一个组件的重新渲染,从而达到了我们的预期需求:只有发生改变的地方需要重新渲染。实际开发的时候只需要将可能会发生改变的组件独立出来,每次只更新一个组件或几个组件。尽可能减少render函数的负担,提高react-native的重绘能力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class MyState {
@observable num1 = 0;
@observable num2 = 100;

@action addNum1 = () => {
this.num1 ++;
};
@action addNum2 = () => {
this.num2 ++;
};
}

const newState = new MyState();

const AllNum = observer((props) => {
console.log('刷新all');
return (
<View>
<Text>num2 = {props.store.num2}</Text>
<View>
<Button onPress={props.store.addNum2} title="button2" />
</View>
</View>
);
});

const Main = observer((props) => {
console.log('刷新main');
return (
<View>
<Text>num1 = {props.store.num1}</Text>
<View>
<Button onPress={props.store.addNum1} title="button1" />
</View>
</View>
);
});

@observer
export default class Asset extends PureComponent {
render() {
return (
<View>
<Main store={newState} />
<AllNum store={newState} />
</View>
);
}
}

引入mobx做为项目的数据管理,势必会带来代码量增加等问题。我们可以在项目目录结构上作出相应调整,以便于更好的开发。

以功能为标准划分

将文件夹按照功能区分,比如pages下存放所有的页面,logics下存放所有的mobx的逻辑等。

这样的结构可以一眼就划分出每个js的功能,每个文件夹下存放着相同功能的js。

带来的问题就是,页面与逻辑不在一个地方。查找起来十分麻烦,pages下的子目录与logics下的子目录结构是相似的或者是相同的,刚接触的时候容易搞混。当功能变动,或者是整体迁移的时候,涉及页面零散不易拆分。

以模块为标准划分

文件夹按照一个个页面功能划分,如首页、注册登录模块、我的模块等,每个文件夹下存放该模块的页面、逻辑等所有涉及到该模块的代码。

这样的划分的好处是,文件结构可以与设计的页面对应起来。划分出一个个独立的模块,实现该模块的所有或者说大部分的代码都在同一个文件夹,易于拆分。

但当模块与模块之间有交互或者跳转的时候,就会横跨几个文件夹,难以对照。又或者模块之间有共用组件的时候就变得十分难以划分。无论将共用组件放到哪里,都不合适。放在其中一个模块中,另一个模块去引用的时候十分困难。两边都放上代码,但是十分麻烦。要是再用一个与模块同级的文件夹,那各个模块又不能真正“独立”起来。