配置 {🚀}
MobX 根据您使用它的方式、要定位的 JavaScript 引擎以及是否希望 MobX 提示最佳实践,提供了几种配置。大多数配置选项可以使用 configure
方法设置。
代理支持
默认情况下,MobX 使用代理来使数组和普通对象可观察。代理提供了最佳性能和跨环境的一致性行为。但是,如果您要定位不支持代理的环境,则必须禁用代理支持。最值得注意的是,当您定位 Internet Explorer 或不使用 Hermes 引擎的 React Native 时,情况就是这样。
可以使用 configure
禁用代理支持
import { configure } from "mobx"
configure({
useProxies: "never"
})
useProxies
配置的接受值为
"always"
(默认): MobX 预计只在具有Proxy
支持 的环境中运行,如果不存在这样的环境,它将报错。"never"
: 不使用代理,MobX 回退到非代理替代方案。这与所有 ES5 环境兼容,但会导致各种 限制。"ifavailable"
(实验性): 如果代理可用,则使用代理,否则 MobX 回退到非代理替代方案。这种模式的优点是,MobX 会尝试在使用 ES5 环境中无法使用的 API 或语言特性时发出警告,从而在现代环境中遇到 ES5 限制时触发错误。
注意: 在 MobX 6 之前,必须选择 MobX 4 用于旧引擎,或 MobX 5 用于新引擎。但是,MobX 6 支持两者,尽管在定位旧 JavaScript 引擎时需要为某些 API(如 Map)提供垫片。代理无法垫片化。即使存在垫片,它们也不支持完整的规范,不适合 MobX。不要使用它们。
没有代理支持的限制
- 可观察数组不是真正的数组,因此它们不会通过
Array.isArray()
检查。实际结果是,您通常需要先.slice()
数组(获取真实数组的浅拷贝),然后才能将其传递给第三方库。例如,连接可观察数组不会按预期工作,因此请先.slice()
它们。 - 在创建后添加或删除现有可观察普通对象的属性不会自动被拾取。如果您打算将对象用作基于索引的查找映射,换句话说,用作事物的动态集合,请使用可观察映射。
即使在没有启用代理的情况下,也可以动态地向对象添加属性并检测它们的添加。这可以通过使用 集合实用程序 {🚀} 来实现。确保使用 set
实用程序设置(新)属性,并使用 values
/ keys
或 entries
实用程序中的一个来迭代对象,而不是使用内置的 JavaScript 机制。但是,由于这很容易忘记,我们建议尽可能使用可观察映射。
装饰器支持
有关启用实验性装饰器支持,请查看 启用装饰器 {🚀} 部分。
代码风格检查选项
为了帮助您采用 MobX 提倡的模式,严格区分动作、状态和派生,MobX 可以通过提示代码风格问题来“代码风格检查” 您的编码模式。为了确保 MobX 尽可能严格,请采用以下设置,并阅读对它们的解释
import { configure } from "mobx"
configure({
enforceActions: "always",
computedRequiresReaction: true,
reactionRequiresObservable: true,
observableRequiresReaction: true,
disableErrorBoundaries: true
})
在某些时候,您会发现这种严格程度可能很烦人。一旦您确定自己(和您的同事)理解了 MobX 的心理模型,就可以禁用这些规则以提高效率。
此外,有时您会遇到必须抑制这些规则触发的警告的情况(例如,通过包装在 runInAction
中)。这很好,这些建议有一些好的例外情况。不要对它们教条主义。
请务必尝试我们的 eslint
插件。虽然有些问题可以静态地发现,但另一些问题只能在运行时检测到。该插件旨在补充这些规则,而不是替代它们。自动修复功能也可以帮助您处理样板代码。
enforceActions
enforceActions 的目标是让您不要忘记将事件处理程序包装在 action
中。
可能的选项
"observed"
(默认): 所有在某处被观察到的状态都需要通过动作来更改。这是默认值,也是非平凡应用程序中推荐的严格模式。"never"
: 状态可以在任何地方更改。"always"
: 状态始终需要通过动作来更改,实际上这也包括创建。
"observed"
的好处是它允许您在动作之外创建可观察对象并自由地修改它们,只要它们尚未在任何地方使用。
由于原则上状态始终应该从某些事件处理程序创建,而事件处理程序应该被包装,因此 "always"
最好地捕获了这一点。但是,您可能不希望在单元测试中使用这种模式。
在您懒惰地创建可观察对象(例如在计算属性中)的罕见情况下,您可以使用 runInAction
将创建临时地包装在动作中。
computedRequiresReaction: boolean
禁止从动作或反应之外直接访问任何未观察到的计算值。这保证您不会以 MobX 不会缓存它们的方式使用计算值。默认值: false
。
在以下示例中,MobX 不会在第一个代码块中缓存计算值,但在第二个和第三个代码块中会缓存结果
class Clock {
seconds = 0
get milliseconds() {
console.log("computing")
return this.seconds * 1000
}
constructor() {
makeAutoObservable(this)
}
}
const clock = new Clock()
{
// This would compute twice, but is warned against by this flag.
console.log(clock.milliseconds)
console.log(clock.milliseconds)
}
{
runInAction(() => {
// Will compute only once.
console.log(clock.milliseconds)
console.log(clock.milliseconds)
})
}
{
autorun(() => {
// Will compute only once.
console.log(clock.milliseconds)
console.log(clock.milliseconds)
})
}
observableRequiresReaction: boolean
警告任何未观察到的可观察访问。如果您想检查是否在没有“MobX 上下文”的情况下使用可观察对象,请使用此选项。这是查找任何缺少的 observer
包装器(例如在 React 组件中)的好方法。但它也会找到缺少的动作。默认值: false
configure({ observableRequiresReaction: true })
注意: 在用 observer
包装的组件上使用 propTypes 可能会为此规则触发误报。
reactionRequiresObservable: boolean
当在没有访问任何可观察对象的情况下创建反应(例如 autorun
)时发出警告。使用此选项来检查是否不必要地用 observer
包装 React 组件,用 action
包装函数,或者查找您只是忘记使某些数据结构或属性可观察的情况。默认值: false
configure({ reactionRequiresObservable: true })
disableErrorBoundaries: boolean
默认情况下,MobX 会捕获并重新抛出您的代码中发生的异常,以确保一个异常中的反应不会阻止其他可能无关的反应的计划执行。这意味着异常不会传播回导致异常的原始代码,因此您无法使用 try/catch 捕获它们。
通过禁用错误边界,异常可以逃逸派生。这可能会简化调试,但可能会使 MobX 以及扩展到您的应用程序处于不可恢复的损坏状态。 默认值:false
。
此选项非常适合单元测试,但请记住在每次测试后调用 _resetGlobalState
,例如通过在 jest 中使用 afterEach
,例如
import { _resetGlobalState, observable, autorun, configure } from "mobx"
configure({ disableErrorBoundaries: true })
test("Throw if age is negative", () => {
expect(() => {
const age = observable.box(10)
autorun(() => {
if (age.get() < 0) throw new Error("Age should not be negative")
})
age.set(-1)
}).toThrow("Age should not be negative")
})
afterEach(() => {
_resetGlobalState()
})
safeDescriptors: boolean
MobX 使某些字段 不可配置 或 不可写,以防止您执行不支持的操作或可能破坏您的代码的操作。但是,这也会阻止您在测试中进行 监视/模拟/存根。configure({ safeDescriptors: false })
禁用此安全措施,使所有内容都 可配置 和 可写。请注意,它不会影响现有的可观察对象,只影响之后创建的可观察对象。 谨慎使用 并且仅在需要时使用 - 不要为所有测试全局关闭它,否则您可能会遇到误报(通过包含错误代码的测试)。 默认值:true
configure({ safeDescriptors: false })
其他配置选项
isolateGlobalState: boolean
当在同一个环境中有多个 MobX 实例处于活动状态时,隔离 MobX 的全局状态。当您有一个使用 MobX 的封装库,与使用 MobX 的应用程序位于同一个页面时,这很有用。当您从库中调用 configure({ isolateGlobalState: true })
时,库内部的反应性将保持自包含。
没有此选项,如果多个 MobX 实例处于活动状态,它们的内部状态将被共享。这样做的好处是,来自两个实例的可观察对象可以协同工作,缺点是 MobX 版本必须匹配。 默认值:false
configure({ isolateGlobalState: true })
reactionScheduler: (f: () => void) => void
设置一个新的函数来执行所有 MobX 反应。默认情况下,reactionScheduler
只运行 f
反应,没有任何其他行为。这对于基本调试或减慢反应速度以可视化应用程序更新很有用。 默认值:f => f()
configure({
reactionScheduler: (f): void => {
console.log("Running an event after a delay:", f)
setTimeout(f, 100)
}
})