autorun(() => {
console.log("Tasks left: " + todos.unfinishedTodoCount)
})
MobX 会对什么作出响应?
为什么每次 unfinishedTodoCount 变化时都会打印一条新消息?答案就是下面这条经验法则:
MobX 会对在执行跟踪函数期间读取的任何现有的可观察属性做出反应。
定义的ts文件
import { observable, action } from 'mobx'
class CallCeter {
//监听
@observable mobile: string = ''
@observable callName: string = ''
//修改状态
@action
setMobile(value: string) {
this.mobile = value
}
@action
setCallName(value: string) {
this.callName = value
}
}
export default new CallCeter()
tsx文件
import React, { Fragment, useEffect, useReducer, useState } from 'react';
import { useStores } from '@/store/index.ts'
import { autorun, computed, toJS, reaction, when } from 'mobx';
import { useLocalStore, useObserver, observer } from 'mobx-react'
const AddressBook: React.FC = () => {
const store = useStores()
const { callCenterStore } = store
// 修改状态
const callOk = () => {
callCenterStore.setCallName(rowData.customerName)
}
// when(),接收两个函数为参数,第一个函数根据引入的可观察数据返回布尔值,当布尔值为true时,则执行第二个函数
//(when提供了条件执行逻辑)
when(() => Boolean(window.localStorage.getItem('customerId')), () => {
})
// 接收两个函数参数,第一个函数根据可观察函数,数据变化后,返回一个新的值,该值作为第二个函数的参数
reaction(() => (callCenterStore.wsReceived), () => {
if (callCenterStore.wsReceived.type === 'ACTION_CALLING') {
...
}
})
// useObserver包裹的dom会动态监听store值的变化来更新dom
return useObserver(() => (
<>
</>
))
}
export default AddressBook
1、安装
npm install mobx
npm install mobx-react
2、mobx要点
1、定义状态并使其可观察
可定义任何数据类型变量
import {observable} from 'mobx';
var appState = observable({
timer: 0
});
2、创建视图以响应状态
当 appState 中相关数据发生改变时视图会自动更新。
import {observer} from 'mobx-react';
@observer
class TimerView extends React.Component {
render() {
return (
<button onClick={this.onReset.bind(this)}>
Seconds passed: {this.props.appState.timer}
</button>
);
}
onReset() {
this.props.appState.resetTimer();
}
};
ReactDOM.render(<TimerView appState={appState} />, document.body);
3、更改状态
下面的代码每秒都会修改你的数据,而当需要的时候UI会自动更新。 无论是在改变状态的控制器函数中,还是在应该更新的视图中,都没有明确的关系定义。 使用 observable 来装饰你的状态和视图,这足以让 MobX检测所有关系了。
appState.resetTimer = action(function reset() {
appState.timer = 0;
});
setInterval(action(function tick() {
appState.timer += 1;
}), 1000);
3、概念与原则
1、state(状态)
状态是驱动应用的数据,像当前已选元素的视图状态
2、derivations(衍生)
任何源自状态并且不会再有任何进一步的相互作用的东西就是衍生。
衍生以多种形式存在:
- 用户界面
- 衍生数据,比如剩下的待办事项的数量。
- 后端集成,比如把变化发送到服务器端。
MobX 区分了两种类型的衍生:
- Computed values(计算值) :它们是永远可以使用纯函数(pure function)从当前可观察状态中衍生出的值。
- Reactions(反应) :Reactions 是当状态改变时需要自动发生的副作用。需要有一个桥梁来连接命令式编程和响应式编程。或者说得更明确一些,它们最终都需要实现I / O 操作。
3、action (动作)
动作 是任一一段可以改变状态的代码
MobX 支持单向数据流,也就是动作改变状态,而状态的改变会更新所有受影响的视图。
实例:
import {observable, autorun} from 'mobx';
var todoStore = observable({
/* 一些观察的状态 */
todos: [],
/* 推导值 */
get completedCount() {
return this.todos.filter(todo => todo.completed).length;
}
});
/* 观察状态改变的函数 */
autorun(function() {
console.log("Completed %d of %d items",
todoStore.completedCount,
todoStore.todos.length
);
});
/* ..以及一些改变状态的动作 */
todoStore.todos[0] = {
title: "Take a walk",
completed: false
};
// -> 同步打印 'Completed 0 of 1 items'
todoStore.todos[0].completed = true;
// -> 同步打印 'Completed 1 of 1 items'
4、API
监听
Observable(value)
用法:
observable(value)
@observable time = ''
observable.box(value, options?)
创建一个 observable 的盒子,它用来存储value的 observable 引用。使用 get() 方法可以得到盒子中的当前value,而使用 set() 方法可以更新value。 这是所有其它 observable 创建的基础,但实际中你其实很少能使用到它。
具体参考官方文档
装饰器
decorators
使用装饰器可以很好地调节通过 observable、 extendObservable 和 observable.object 定义的属性的可观察性。它们还可以控制特定属性的自动转换规则。
可用的装饰器列表:
- observable.deep: 所有 observable 都使用的默认的装饰器。它可以把任何指定的、非原始数据类型的、非 observable 的值转换成 observable。
- observable.ref: 禁用自动的 observable 转换,只是创建一个 observable 引用。
- observable.shallow: 只能与集合组合使用。 将任何分配的集合转换为浅 observable (而不是深 observable)的集合。 换句话说, 集合中的值将不会自动变为 observable。
- computed: 创建一个衍生属性
- action: 创建一个动作
- action.bound: 创建有范围的动作
可以使用 @decorator 语法来应用这些装饰器:
@observable,@action
import {observable, action} from 'mobx';
class TaskStore {
@observable.shallow tasks = []
@action addTask(task) { /* ... */ }
}
计算属性
computed
用法:
* computed(() => expression)
* computed(() => expression, (newValue) => void)
* computed(() => expression, options)
* @computed({equals: compareFn}) get classProperty() { return expression; }
* @computed get classProperty() { return expression; }
动作
Action 动作是用来修改状态的东西
用法:
* action(fn)
* action(name, fn)
* @action classMethod
* @action(name) classMethod
* @action boundClassMethod = (args) => { body }
* @action.bound boundClassMethod(args) { body }