Я много раз использовал Redux и всегда слышал, что Mobx может заставить вас испытать ощущение написания Vue в React.Сегодня я планирую попробовать посмотреть, действительно ли Mobx похоже на написание Vue.
Не по теме
Прежде чем рассказать об использовании MobX, давайте сделаем отступление: мы можем взглянуть на китайское введение MobX. На китайском сайте MobX написано:
MobX — это разрушенная войной библиотека, которая делает управление состоянием простым и расширяемым за счет прозрачного функционального реактивного программирования.
«Библиотека боевого крещения» кажется очень странной, и ее очень трудно читать, и многие статьи о MobX в Интернете написаны именно так.githubПросматривая его README, обнаружил, что он написал:
MobX is a battle tested library that makes state management simple and scalable by transparently applying functional reactive programming (TFRP).
Видно, что автор изначально намеревался показать, что MobX прошел множество тестов и обладает относительно высокой надежностью. Ниже приводится результат, переведенный Google, который кажется более точным, чем выражение на китайском веб-сайте.
Хотя мой уровень английского также очень хорош, я постараюсь прочитать официальные документы, чтобы избежать ненужных недоразумений.
как использовать?
Ближе к дому, последняя версия MobX 6.0, По сравнению с предыдущей версией, API этой версии был значительно упрощен, и можно сказать, что его проще использовать. Предыдущая версия была синтаксическим сахаром в стиле декоратора, но декоратор не является зрелым в текущей спецификации ES, а введение синтаксиса декоратора также увеличивает размер упакованного кода. Учитывая все обстоятельства, MobX 6.0 удалил API для синтаксиса декоратора.
реактивный объект
Пропуск MobXmakeObservable
метод создания реактивного объекта, свойства входящего объекта будут передаваться черезProxy
Прокси, похожие на Vue, используемые до версии 6.0Object.defineProperty
API, конечно же, 6.0 также предоставляет схему перехода на более раннюю версию.
import { configure, makeObservable, observable, action, computed } from 'mobx'
// 使用该配置,可以将 Proxy 降级为 Object.defineProperty
configure({ useProxies: "never" });
// 构造响应对象
const store = makeObservable(
// 需要代理的响应对象
{
count: 0,
get double() {
return this.count * 2
},
increment() {
this.count += 1
},
decrement() {
this.count -= 1
}
},
// 对各个属性进行包装,用于标记该属性的作用
{
count: observable, // 需要跟踪的响应属性
double: computed, // 计算属性
increment: action, // action 调用后,会修改响应对象
decrement: action, // action 调用后,会修改响应对象
}
)
Мы смотрим на предыдущие версии MobX, используя декораторы:
class Store {
@observable count = 0
constructor() {
makeObservable(this)
}
@action increment() {
this.count++;
}
@action decrement() {
this.count--;
}
@computed get double() {
return this.count * 2
}
}
const store = new Store()
Таким образом, кажется, что метод написания не упростился, и он кажется более сложным, чем написание декораторов. Давайте взглянем на более мощный API в версии 6.0:makeAutoObservable
.
makeAutoObservable
сильнееmakeObservable
, вы можете автоматически добавлять функции-оболочки объектов к атрибутам, и стоимость начала работы резко снизится.
import { makeAutoObservable } from 'mobx'
const store = makeAutoObservable({
count: 0,
get double() {
return this.count * 2
},
increment() {
this.count += 1
},
decrement() {
this.count -= 1
}
})
вычисляемое свойство
Свойства MobX и Vuecomputed
то же, вmakeAutoObservable
в одномgetter
,getter
Как только зависимое значение изменится,getter
Соответственно изменится и само возвращаемое значение.
import { makeAutoObservable } from 'mobx'
const store = makeAutoObservable({
count: 0,
get double() {
return this.count * 2
}
})
когдаstore.count
Когда 1, позвонитеstore.double
вернется 2.
изменить поведение
Когда нам нужно изменить свойство ответа в магазине, мы можем изменить его, напрямую переназначив его, но это приведет к предупреждению от MobX⚠️.
const store = makeAutoObservable({
count: 0
});
document.getElementById("increment").onclick = function () {
store.count += 1
}
MobX подскажет, что при изменении свойств отзывчивого объекта его необходимо изменить действием. Хотя прямая модификация также может вступить в силу, она сделает управление состоянием MobX более запутанным, а введение модификации состояния в действие может позволить MobX изменить внутренний процесс транзакции, чтобы не получить определенный атрибут, все еще находящийся в промежуточном состоянии. state , окончательный результат расчета недостаточно точен.
makeAutoObservable
Все методы будут обрабатываться как действия.
import { makeAutoObservable } from 'mobx'
const store = makeAutoObservable({
count: 0,
get double() {
return this.count * 2
},
increment() { // action
this.count += 1
},
decrement() { // action
this.count -= 1
}
})
В отличие от Vuex, модификация состояния делится на мутацию и действие, синхронная модификация помещается в мутацию, а асинхронная операция помещается в действие. В MobX, будь то синхронная или асинхронная операция, ее можно поместить в действие, но когда асинхронная операция изменяет атрибут, операцию присваивания необходимо поместить в действие.runInAction
середина.
import { runInAction, makeAutoObservable } from 'mobx'
const store = makeAutoObservable({
count: 0,
async initCount() {
// 模拟获取远程的数据
const count = await new Promise((resolve) => {
setTimeout(() => {
resolve(10)
}, 500)
})
// 获取数据后,将赋值操作放到 runInAction 中
runInAction(() => {
this.count = count
})
}
})
store.initCount()
если не позвалиrunInAction
, вы можете напрямую вызвать действие, которое уже существует.
import { runInAction, makeAutoObservable } from 'mobx'
const store = makeAutoObservable({
count: 0,
setCount(count) {
this.count = count
},
async initCount() {
// 模拟获取远程的数据
const count = await new Promise((resolve) => {
setTimeout(() => {
resolve(10)
}, 500)
})
// 获取数据后,调用已有的 action
this.setCount(count)
}
})
store.initCount()
Отслеживание изменений объекта
Если вы хотите внедрить MobX в React или в небольшую программу, вам необходимо уведомлять о вызове натива при изменении объекта.setState/setData
метод для синхронизации состояния с представлением.
пройти черезautorun
метод может достичь этой способности, мы можем положитьautorun
Поймите это как React HooksuseEffect
. Всякий раз, когда изменяется свойство ответа хранилища, передайтеautorun
Методы(effect
) будет вызван один раз.
import { autorun, makeAutoObservable } from 'mobx'
const store = makeAutoObservable({
count: 0,
setCount(count) {
this.count = count
},
increment() {
this.count++
},
decrement() {
this.count--
}
})
document.getElementById("increment").onclick = function () {
store.count++
}
const $count = document.getElementById("count")
$count.innerText = `${store.count}`
autorun(() => {
$count.innerText = `${store.count}`
})
в любое времяbutton#increment
Когда кнопка нажата,span#count
Значения внутри автоматически синхронизируются. 👉Посмотреть полный код.
Кромеautorun
, MobX также предоставляет более совершенный метод мониторинга:reaction
,when
.
const store = makeAutoObservable({
count: 0,
setCount(count) {
this.count = count
},
increment() {
this.count++
},
decrement() {
this.count--
}
})
// store 发生修改立即调用 effect
autorun(() => {
$count.innerText = `${store.count}`
});
// 第一个方法的返回值修改后才会调用后面的 effect
reaction(
// 表示 store.count 修改后才会调用
() => store.count,
// 第一个参数为当前值,第二个参数为修改前的值
// 有点类似与 Vue 中的 watch
(value, prevValue) => {
console.log('diff', value - prevValue)
}
);
// 第一个方法的返回值为真,立即调用后面的 effect
when(() => store.count > 10, () => {
console.log(store.count)
})
// when 方法还能返回一个 promise
(async function() {
await when(() => store.count > 10)
console.log('store.count > 10')
})()
Суммировать
Знакомство с MobX закончено, в этой статье лишь кратко перечислены API-интерфейсы MobX, и я надеюсь, что каждый сможет что-то для себя извлечь. В будущем планирую подробно изучить реализацию MobX.После изучения напишу статью, чтобы поделиться.