【前端知识】简单,可扩展的状态管理组件MobX
文章目录
概念
MobX区分了应用程序中的以下三个概念:
- State(状态)
- Actions(动作)
- Derivations(派生)
让我们仔细看看下面的这些概念,或者在10分钟的MobX和React简介中,您可以通过交互方式逐步深入了解这些概念,并构建一个简单的待办事项列表(Todo List)应用程序。
1. 定义 State 并使其可观察
State(状态) 是驱动你的应用程序的数据。
通常来说,状态有_领域特定状态_(比如 Todo List 中的列表项数据)和_视图状态_ (比如当前选中的列表元素)。State 就像保存着数据的电子表格单元格一样。
将 State 存储在任何您喜欢的数据结构中:普通对象、数组、类、循环数据结构或引用。这与MobX的工作方式无关。
只要确保所有你想随时间改变的属性都被标记为observable,这样MobX就可以跟踪它们。
以下是一个简单的示例:
import { makeObservable, observable, action } from "mobx"
class Todo {
id = Math.random()
title = ""
finished = false
constructor(title) {
makeObservable(this, {
title: observable,
finished: observable,
toggle: action
})
this.title = title
}
toggle() {
this.finished = !this.finished
}
}
- 提示: 在这个例子中我们可以用
makeAutoObservable
对其进行简化,但是为了能更详细的展示不同的概念,我们对其进行显式设置。
使用 observable
就像将对象的属性放在Excel表格的单元格中。但是和单元格不同的是,他们的值不仅仅是数值,也可以是引用、对象和数组。
接下来我们看一下被我们标记为 action
的toggle
2. 使用 Action 更新 State
Action(动作) 是任意可以改变 State(状态) 的代码,比如用户事件处理、后端推送数据处理、调度器事件处理等等。
Action 就像用户在Excel单元格中输入了新的值。
在 Todo
类中,我们可以看到 toggle
方法改变了 finished
属性的值,而 finished
是被标记为 observable
的。建议您将所有修改 observable
值的代码标记为 action
。MobX 可以自动进行事务处理以轻松实现最佳性能。
使用 Action 可以帮助您更好地组织代码,并防止您在无意中修改 State。
在 MobX 术语中,可以修改 State 的方法被称为 action(动作) 。这与基于当前状态来生成新信息的 view(视图) 是不同的。 您代码中的每一个方法只应完成上述两个目标中的一个。
3. 创建 Derivations 以便自动对 State 变化进行响应
任何 来源是_State(状态)_ 并且不需要进一步交互的东西都是 Derivation(派生)。
Derivations 包括许多方式:
- 用户界面
- 派生数据 , 比如剩余未完成
todos
的数量 - 后端集成 , 比如发送改变到服务器端
Mobx 区分了两种 Derivation :
- Computed values,总是可以通过纯函数从当前的可观测 State 中派生。
- Reactions, 当 State 改变时需要自动运行的副作用 (命令式编程和响应式编程之间的桥梁)
当最开始使用MobX时,人们容易过度使用 Reaction。
黄金法则是,如果要基于当前 State 创建值,请始终使用 computed。
3.1. 通过 computed 对派生值进行建模
你可以通过定义 getter 方法并使用 makeObservable
将其标记为 computed
的方式创建一个 computed
值。
import { makeObservable, observable, computed } from "mobx"
class TodoList {
todos = []
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
constructor(todos) {
makeObservable(this, {
todos: observable,
unfinishedTodoCount: computed
})
this.todos = todos
}
}
Mobx 会确保 unfinishedTodoCount
会在todos数组发生变化中或者 todos
中的一个对象中的 finished
属性被修改时自动更新。
这些计算类似于 Excel 单元格中的公式。它们仅在需要时自动更新。也就是说,如果有观察者使用其结果时才会更新。也就是说,如果有有人关心其结果时才会更新。
3.2. 使用 reaction 对副作用建模
作为用户,要想在屏幕上看到状态或计算值的变化,就需要一个重新绘制部分GUI的 reactions 。
Reaction 和 computed 类似,但并不产生信息,而是产生副作用,如打印到控制台、发出网络请求、增量更新 React 组件树以便更新DOM等。
简而言之,reaction 是 响应式编程和指令式编程之间的桥梁。
到目前为止,最常用的 reaction 形式是UI组件。 注意,action 和 reaction 都可能引起副作用。 副作用应有一个清晰的、显式的起源,例如在提交表单时发出网络请求,应该从相关的事件处理程序显式触发。
3.3. 响应式 React 组件
如果使用 React,你可以将组件用安装中下载的包中的observer函数来包装起来,以便让组件成为响应式的。在这个示例中,我们将用更轻量的 mobx-react-lite 包。
import * as React from "react"
import { render } from "react-dom"
import { observer } from "mobx-react-lite"
const TodoListView = observer(({ todoList }) => (
<div>
<ul>
{todoList.todos.map(todo => (
<TodoView todo={todo} key={todo.id} />
))}
</ul>
Tasks left: {todoList.unfinishedTodoCount}
</div>
))
const TodoView = observer(({ todo }) => (
<li>
<input type="checkbox" checked={todo.finished} onClick={() => todo.toggle()} />
{todo.title}
</li>
))
const store = new TodoList([new Todo("Get Coffee"), new Todo("Write simpler code")])
render(<TodoListView todoList={store} />, document.getElementById("root"))
observer
将 React 组件转化为了从数据到渲染的派生过程。 当使用 MobX 时,不存在“智能组件”和“木偶组件”。所有的组件在渲染时都是智能的,但是在定义时是按照木偶组件的方式去定义的。MobX会简单确定这个组件是否需要进行重绘,并止步于此。
因此,上述示例中的onClick
事件处理器调用toggle Action
后,会使对应的TodoView
组件重绘,但仅当未完成任务的数量发生更改时才会使 TodoListView 组件重绘。
如果移除了Tasks left
这行代码(或者把他拆分到另一个组件中),TodoListView组件就不再 toggle 执行时产生重绘了。
您可以查阅与 React 集成来了解更多有关 React 是如何与 MobX 协同运作的。
3.4. 自定义 Reaction
通常情况下你不需要使用它们,可以使用 autorun ,reaction 或 when 方法来订制你的特殊业务场景。
比如,下面的 autorun 将在unfinishedTodoCount的数量发生变化时输出日志。
// 一个自动观察state的函数
autorun(() => {
console.log("Tasks left: " + todos.unfinishedTodoCount)
})
为什么每次 unfinishedTodoCount
发生改变时都会输出日志信息呢?答案是以下法则:
MobX对在执行跟踪函数期间读取的任何现有可观察属性作出响应。
要了解更多关于MobX如何确定需要对哪些可观察对象作出响应的信息,请查看 理解响应性 章节。
原则
Mobx 使用单向数据流,利用 action 改变 state ,进而更新所有受影响的 view
- 所有的 derivations 将在 state 改变时自动且原子化地更新。因此不可能观察中间值。
- 所有的 derivations 默认将会同步更新,这意味着 action 可以在 state 改变 之后安全的直接获得 computed 值。
- computed value 的更新是惰性的,任何 computed value 在需要他们的副作用发生之前都是不激活的。
- 所有的 computed value 都应是纯函数,他们不应该修改 state。
API参考
MobX是一个强大的状态管理库,其API提供了丰富的功能来支持响应式编程。以下是对MobX API的详细参考:
一、核心API
-
observable
- 功能:将对象、数组、Map、Set等数据结构转换为可观察的状态。
- 用法:
observable(source, overrides?, options?)
:克隆一个对象并把它转化成observable。source可以是一个普通的对象、数组、Map或Set。observable.object(source, overrides?, options?)
:observable
的别名,创建一个被传入对象的副本并使它的所有属性observable。observable.array(initialValues?, options?)
:基于所提供的initialValues创建一个新的observable数组。observable.map(initialMap?, options?)
:基于所提供的initialMap创建一个新的observable ES6 Map。observable.set(initialSet?, options?)
:根据所提供的initialSet创建一个新的observable ES6 Set。observable.ref(annotation)
:和observable
注解类似,但只有重新赋值会被追踪。所赋的值本身并不会被自动转化成observable。observable.shallow(annotation)
:和observable.ref
注解类似,但用于集合。任何所赋的集合都会被转化成observable,但是集合本身的内容不会被转化成observable。observable.struct(annotation)
:和observable
注解类似,但是与现有值结构相等的任何赋值都会被忽略。observable.deep(annotation)
:observable
注解的别名。observable.box(value, options?)
:JavaScript中的所有原始值都是不可变的,所以它们都不是observable。可以创建一个observable box来管理这种原始值。
-
makeObservable
- 功能:将目标对象中的属性和方法设置为observable state和action。
- 用法:
makeObservable(target, annotations?, options?)
。
-
makeAutoObservable
- 功能:自动将属性、对象、数组、Maps和Sets转化成observable,并同时处理actions和computed。
- 用法:
makeAutoObservable(target, overrides?, options?)
。
-
extendObservable
- 功能:在target对象上引入新属性并立即把它们全部转化成observable。
- 用法:
extendObservable(target, properties, overrides?, options?)
。
二、其他API
MobX还提供了许多其他API来支持更复杂的场景和调试需求,如reaction
、autorun
、when
、configure
等。这些API在MobX的官方文档中都有详细的介绍和示例。
三、使用示例
以下是一个简单的使用示例,展示了如何使用MobX来管理React组件的状态:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { makeAutoObservable } from 'mobx';
import { Provider, observer } from 'mobx-react';
// 定义一个store来管理状态
class Store {
count = 0;
constructor() {
makeAutoObservable(this);
}
increment() {
this.count++;
}
}
const store = new Store();
// 定义一个响应式组件
const Counter = observer(() => {
return (
<div>
<p>Count: {store.count}</p>
<button onClick={() => store.increment()}>Increment</button>
</div>
);
});
// 使用Provider将store提供给组件树
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<Provider store={store}>
<Counter />
</Provider>
);
在这个示例中,我们定义了一个Store
类来管理状态,并使用makeAutoObservable
来将其属性和方法转换为observable和action。然后,我们定义了一个响应式组件Counter
,它使用observer
高阶组件来订阅store的状态变化。最后,我们使用Provider
将store提供给组件树,这样Counter
组件就可以访问和响应store的状态变化了。
总的来说,MobX的API提供了强大的功能来支持响应式编程和状态管理,使得开发者可以更加高效地构建和维护复杂的React应用。
原文地址:https://blog.csdn.net/wendao76/article/details/144302652
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!