【React】MobX
概述
mobx 实现像 vue 一样声明式的修改数据,我们在项目中直接使用 mobx + mobx-react 。
mobxjs/mobx-react: React bindings for MobX (github.com)
https://zh.mobx.js.org/the-gist-of-mobx.html
-
state 数据
-
action 动作
-
derivation 派生
- computed
observer
监听变化,包裹的 React 组件autorun
监听变化,像 watch
computed 必须是纯函数。而 action 可以修改 state (如 arr.push) 。
computed 采用惰性求值,会缓存其输出,并且只有当其依赖的可观察对象被改变时才会重新计算。 它们在不被任何值观察时会被暂时停用。
npm install mobx-react mobx --save
使用
import React, {FC, useEffect} from 'react';
import {action, makeAutoObservable, makeObservable, observable} from "mobx";
import {observer} from "mobx-react";
class Timer {
secondsPassed = 0;
constructor() {
// 使该类的所有属性变成响应式(自动)
// makeAutoObservable(this)
// 使该类的所有属性变成响应式(手动)
makeObservable(this, {
secondsPassed: observable,
increment: action,
reset: action
})
}
increment(count:number) {
this.secondsPassed += count;
}
reset() {
this.secondsPassed = 0;
}
}
const myTimer = new Timer()
type PropsType = { timer: Timer }
const TimerView = observer((props: PropsType) => {
const {timer} = props
return <button onClick={() => timer.reset()}>
seconds passed : {timer.secondsPassed}
</button>
})
const BasicDemo: FC = () => {
useEffect(() => {
const id = setInterval(() => myTimer.increment(10), 1000);
return () => clearInterval(id);
}, []);
return <div>
<p>Basic Demo</p>
<TimerView timer={myTimer}/>
</div>
}
export default BasicDemo;
案例
index.tsx
<TodoList store={store}/>
store.ts
import { nanoid } from 'nanoid'
import { makeObservable, observable, action, computed } from 'mobx'
// Todo class
export class ObservableTodoStore {
id = ''
task = ''
completed = false
constructor(task: string) {
makeObservable(this, {
id: observable,
task: observable,
completed: observable,
rename: action,
toggleCompleted: action
})
this.id = nanoid(5)
this.task = task
}
rename(newName: string) {
this.task = newName
}
toggleCompleted() {
this.completed = !this.completed
}
}
// TodoList class
export class ObservableTodoListStore {
todos: ObservableTodoStore[] = []
constructor() {
makeObservable(this, {
todos: observable,
completedTodosCount: computed, // 计算
addTodo: action,
removeTodo: action
})
}
// get(用于计算,不用于修改) 获取已经完成的 todos 数量
get completedTodosCount() {
return this.todos.filter(t => t.completed).length
}
addTodo(task: string) {
const newTodo = new ObservableTodoStore(task)
this.todos.push(newTodo) // 声明式,像 Vue
}
removeTodo(id: string) {
const index = this.todos.findIndex(t => t.id === id)
this.todos.splice(index, 1)
}
}
const store = new ObservableTodoListStore()
export default store
TodoList.tsx
//...
type PropsType = {
store: ObservableTodoListStore
}
const TodoList: FC<PropsType> = observer((props: PropsType) => {});
//...