on
MobX - 初识响应式编程
也许今天学习 MobX 对我来说有点晚了。 但今天还是要看一看什么是 MobX 什么是响应式编程。
什么是MobX?
Simple, scalable state management. 简单,可扩展的状态管理
官方定义非常简洁,甚至没有任何关于响应式
的描述。只是突出了一句状态管理 (state management)。这是为什么呢?
反过来,官方更强调状态管理
。
说状态管理之前,还是想说说响应式
因为在没有了解过MobX的时候,听到最多的一个词就是响应式
。
响应式编程(Reactive Programming)是一种编程范式,它关注于数据流和变化传播。在响应式编程中,应用程序可以轻松地响应和处理数据流中的变化,这使得应用程序能够更好地适应异步、事件驱动的环境,从而提高了可伸缩性和响应速度。
我对响应式的大白话理解(不保证正确)
编程其实很多时候是在对数据进行处理
,有一种特别常见的场景,数据改变后,我们希望做一些对应的操作。可往往最难的,就是不知道数据什么时候改变?
啊,你想要写例子:
- 异步请求接口,操作返回值
- 外部操作改变数值(类似用户输入等),希望对外部操作值进行操作
这些情况都是我们明确知道会发生的,但是不知道多会儿会发生,也不知道多会儿能收到响应。
响应式编程,就是在这些事情发生时,自动的去做一些对应的操作,就像是把一切都准备好,等着它发生一样。
那MobX的响应式是什么样子的呢?
要解释MobX的用法,需要先学会三个重要的概念:
- observable
- observer
- action
observable
当需要跟踪某个值或者对象的变化时,可以用observable
方法将其包裹,这样MobX就能在该值变化时自动完成更新或者一些其它相关的操作。
import { observable } from 'mobx';
const person = observable({
firstName: 'John',
lastName: 'Doe',
age: 30,
});
observer
刚刚只是将一个对象包裹了observable
并跟踪,那真正要更新或完成的操作该如何定义呢?
这时候就需要 observer
,它通常是包裹一个React组件,当数据改变是,组件就会重新渲染
import React from 'react';
import { observer } from 'mobx-react';
const PersonInfo = observer(({ person }) => (
<div>
<h1>{person.firstName} {person.lastName}</h1>
<p>Age: {person.age}</p>
</div>
));
export default PersonInfo;
action
action
则是用来完成修改我们刚刚追踪值的操作。
import { action } from 'mobx';
const updateAge = action((person, newAge) => {
person.age = newAge;
});
const celebrateBirthday = action(person => {
person.age += 1;
});
这时候给出一个完整的例子。
import React from 'react';
import ReactDOM from 'react-dom';
import { observable, action } from 'mobx';
import { observer } from 'mobx-react';
// Observable
const person = observable({
firstName: 'John',
lastName: 'Doe',
age: 30,
});
// Observer
const PersonInfo = observer(({ person }) => (
<div>
<h1>{person.firstName} {person.lastName}</h1>
<p>Age: {person.age}</p>
<button onClick={() => celebrateBirthday(person)}>Celebrate Birthday</button>
</div>
));
// Actions
const celebrateBirthday = action(person => {
person.age += 1;
});
// Render the React component
ReactDOM.render(<PersonInfo person={person} />, document.getElementById('root'));
这样就做到了刚才所说的响应式
,某个值变了,自动完成相应的操作
可能会有这样的疑问
组件的props改变,当然会重新渲染组件,MobX的意义是什么呢?
其实不然。
MobX 可以监控非props内的变量
这样即便这个值不是props中的一员,也可以做到值改变从而重新渲染组件。
Mobx 可以监控对象中的属性值改变
同样都是对象,MobX能监控到对象内部的属性改变。但如果抛开MobX,React是一个潜比较,即便是内部的值变了,其对象引用不变也不会导致组件重新渲染。
注意MobX的监控也是 浅 监控
当我们用observable
来监控一个对象改变时,MobX只能监控到这个对象内部的每一属性所对应的值。
但是如果这个属性本身又是一个对象(比如数组、对象等)那MobX无法得知其内部的改变。
如果想递归知道每个属性的改变,需要使用observable.deep
来进行包裹。
说说状态管理,MobX与Redux的区别是什么?
同为状态管理,MobX和Redux有何不同?
- MobX是响应式的,Redux是函数式的。MobX更关注跟踪数据的变化,Redux更关注数据的变化如何影响应用的状态。
- MobX允许直接通过action来修改state,并将更改自动分发给observer。Redux需要使用纯函数(reducers)来更新状态。reducers接收当前状态和一个action,然后返回一个新的状态。
- 样板代码。Redux需要编写大量的样板代码,比如action types、action creators、reducers、selectors等。MobX则不需要。
- Redux倾向把所有的state集中在一个store中进行维护。MobX则可以有多个store,每个store可以有自己的actions、reducers、selectors等。
- 生态系统。Redux有一个庞大的生态系统,包括中间件、工具、插件等。MobX的生态系统则相对较小。
说说其他响应式编程例子
其实最近因为工作内容与先前不同的原因,阅读了一些Java的代码,发现Java也有响应式编程,看到了Project Reactor,也就是Reactor。
最开始完全没有理解,因为MobX中的响应式可以通过observable
来包裹,完成数据依赖的跟踪,但是Java中的Reactor是如何完成数据跟踪,并做到响应式的呢?
可能我还是带着前端思维去理解一个后端的Reactive框架了。
对于前端来说,响应式更多的是在UI上的交互,MobX关注的是某些值的监控然后做到一些对应的响应。
而后端则是关注数据操作,即便是响应式,也是数据的响应式,响应更多的是对数据的拼装、转换、过滤等。
import reactor.core.publisher.Mono;
public class CombineMonosExample {
public static void main(String[] args) {
Mono<String> firstName = Mono.just("John");
Mono<String> lastName = Mono.just("Doe");
Mono.zip(firstName, lastName)
.map(tuple -> tuple.getT1() + " " + tuple.getT2())
.subscribe(
value -> System.out.println("Value: " + value),
error -> System.err.println("Error: " + error),
() -> System.out.println("Completed")
);
}
}