配置 {🚀}
¥Configuration {🚀}
MobX 有多种配置,具体取决于你喜欢如何使用它、你想要针对哪些 JavaScript 引擎以及你是否希望 MobX 提示最佳实践。大多数配置选项都可以使用 configure
方法进行设置。
¥MobX has several configurations depending on how you prefer to use it, which JavaScript engines you want to target, and whether you want MobX to hint at best practices.
Most configuration options can be set by using the configure
method.
代理支持
¥Proxy support
默认情况下,MobX 使用代理来使数组和普通对象可观察。代理提供跨环境的最佳性能和最一致的行为。但是,如果你的目标环境不支持代理,则必须禁用代理支持。最值得注意的是,在不使用 Hermes 引擎的情况下以 Internet Explorer 或 React Native 为目标时就会出现这种情况。
¥By default, MobX uses proxies to make arrays and plain objects observable. Proxies provide the best performance and most consistent behavior across environments. However, if you are targeting an environment that doesn't support proxies, proxy support has to be disabled. Most notably this is the case when targeting Internet Explorer or React Native without using the Hermes engine.
可以使用 configure
禁用代理支持:
¥Proxy support can be disabled by using configure
:
import { configure } from "mobx"
configure({
useProxies: "never"
})
useProxies
配置可接受的值为:
¥Accepted values for the useProxies
configuration are:
"always"
(默认):MobX 期望仅在具有Proxy
支持 的环境中运行,如果此类环境不可用,则会出错。¥
"always"
(default): MobX expects to run only in environments withProxy
support and it will error if such an environment is not available."never"
:不使用代理,MobX 依赖于非代理替代方案。这与所有 ES5 环境兼容,但会导致各种 limitations。¥
"never"
: Proxies are not used and MobX falls back on non-proxy alternatives. This is compatible with all ES5 environments, but causes various limitations."ifavailable"
(实验):如果代理可用,则使用代理,否则 MobX 会退回到非代理替代方案。这种模式的好处是,如果使用了在 ES5 环境中不起作用的 API 或语言功能,MobX 将尝试发出警告,从而在现代环境中运行时遇到 ES5 限制时触发错误。¥
"ifavailable"
(experimental): Proxies are used if they are available, and otherwise MobX falls back to non-proxy alternatives. The benefit of this mode is that MobX will try to warn if APIs or language features that wouldn't work in ES5 environments are used, triggering errors when hitting an ES5 limitation running on a modern environment.
注意:在 MobX 6 之前,人们必须为旧引擎选择 MobX 4,或者为新引擎选择 MobX 5。然而,MobX 6 支持两者,尽管在针对较旧的 JavaScript 引擎时需要某些 API(例如 Map)的填充。代理不能被多重填充。尽管 polyfill 确实存在,但它们不支持完整规范并且不适合 MobX。不要使用它们。
¥Note: before MobX 6, one had to pick either MobX 4 for older engines, or MobX 5 for new engines. However, MobX 6 supports both, although polyfills for certain APIs like Map will be required when targetting older JavaScript engines. Proxies cannot be polyfilled. Even though polyfills do exist, they don't support the full spec and are unsuitable for MobX. Don't use them.
没有代理支持的限制
¥Limitations without Proxy support
可观察数组不是真正的数组,因此它们不会通过
Array.isArray()
检查。实际结果是,在将数组传递给第三方库之前,你通常需要先对数组进行.slice()
(以获取真实数组的浅表副本)。例如,连接可观察数组无法按预期工作,因此首先对它们进行.slice()
。¥Observable arrays are not real arrays, so they won't pass the
Array.isArray()
check. The practical consequence is that you often need to.slice()
the array first (to get a shallow copy of the real array) before passing it to third party libraries. For example, concatenating observable arrays doesn't work as expected, so.slice()
them first.创建后添加或删除现有可观察普通对象的属性不会自动选取。如果你打算使用对象作为基于索引的查找映射,换句话说,作为事物的动态集合,请使用可观察的映射。
¥Adding or deleting properties of existing observable plain objects after creation is not automatically picked up. If you intend to use objects as index based lookup maps, in other words, as dynamic collections of things, use observable Maps instead.
即使未启用代理,也可以动态向对象添加属性并检测其添加。这可以通过使用 集合实用程序 {🚀} 来实现。确保使用 set
实用程序设置(新)属性,并使用 values
/ keys
或 entries
实用程序之一(而不是内置 JavaScript 机制)迭代对象。但是,由于这确实很容易忘记,因此我们建议如果可能的话使用可观察的映射。
¥It is possible to dynamically add properties to objects, and detect their additions, even when Proxies aren't enabled.
This can be achieved by using the Collection utilities {🚀}. Make sure that (new) properties are set using the set
utility, and that the objects are iterated using one of the values
/ keys
or entries
utilities, rather than the built-in JavaScript mechanisms.
But, since this is really easy to forget, we instead recommend using observable Maps if possible.
装饰器支持
¥Decorator support
要启用实验性装饰器支持,请查看 启用装饰器 {🚀} 部分。
¥For enabling experimental decorator support check out the Enabling decorators {🚀} section.
代码检查选项
¥Linting options
为了帮助你采用 MobX 提倡的模式,即操作、状态和派生之间的严格分离,MobX 可以通过暗示气味在运行时对你的编码模式进行 "lint" 化。为了确保 MobX 尽可能严格,请采用以下设置并继续阅读其解释:
¥To help you adopt the patterns advocated by MobX, a strict separation between actions, state and derivations, MobX can "lint" your coding patterns at runtime by hinting at smells. To make sure MobX is as strict as possible, adopt the following settings and read on for their explanations:
import { configure } from "mobx"
configure({
enforceActions: "always",
computedRequiresReaction: true,
reactionRequiresObservable: true,
observableRequiresReaction: true,
disableErrorBoundaries: true
})
在某些时候,你会发现这种严格程度可能非常烦人。一旦你确定你(和你的同事)掌握了 MobX 的思维模型,就可以禁用这些规则来提高工作效率。
¥At some point you will discover that this level of strictness can be pretty annoying. It is fine to disable these rules to gain productivity once you are sure you (and your colleagues) grokked the mental model of MobX.
另外,有时你会遇到必须抑制这些规则触发的警告的情况(例如通过换行 runInAction
)。没关系,这些建议也有很好的例外。不要对他们持原教旨主义态度。
¥Also, occasionally you will have a case where you have to suppress the warnings triggered by these rules (for example by wrapping in runInAction
).
That is fine, there are good exceptions to these recommendations.
Don't be fundamentalist about them.
请务必尝试一下我们的 eslint
插件。虽然有些问题可以静态发现,但其他问题只能在运行时检测到。该插件旨在补充这些规则,而不是取代它们。自动修复功能还可以帮助处理样板代码。
¥Make sure to also try our eslint
plugin.
While some problems are discoverable statically, others are detectable only at runtime.
The plugin is intended to complement these rules, not to replace them.
The autofix feature can also help with the boilerplate code.
enforceActions
enforceActions 的目标是你不要忘记将事件处理程序封装在 action
中。
¥The goal of enforceActions is that you don't forget to wrap event handlers in action
.
可能的选项:
¥Possible options:
"observed"
(默认):在某处观察到的所有状态都需要通过操作来改变。这是默认的,也是重要应用中推荐的严格模式。¥
"observed"
(default): All state that is observed somewhere needs to be changed through actions. This is the default, and the recommended strictness mode in non-trivial applications."never"
:状态可以从任何地方改变。¥
"never"
: State can be changed from anywhere."always"
:状态总是需要通过动作来改变,实践中也包括创造。¥
"always"
: State always needs to be changed through actions, which in practice also includes creation.
"observed"
的好处是它允许你在操作之外创建可观察量并自由修改它们,只要它们尚未在任何地方使用即可。
¥The benefit of "observed"
is that it allows you to create observables outside of actions and modify them freely, as long as they aren't used anywhere yet.
由于状态原则上应该始终从某些事件处理程序创建,并且应该封装事件处理程序,因此 "always"
最好地捕获了这一点。但你可能不想在单元测试中使用此模式。
¥Since state should in principle always be created from some event handlers, and event handlers should be wrapped, "always"
captures this the best. But you probably don't want to use this mode in unit tests.
在极少数情况下,你会延迟创建可观察量(例如在计算属性中),你可以使用 runInAction
将临时创建封装在操作中。
¥In the rare case where you create observables lazily, for example in a computed property, you can wrap the creation ad-hoc in an action using runInAction
.
computedRequiresReaction: boolean
禁止从动作或反应外部直接访问任何未观察到的计算值。这保证了你不会以 MobX 不会缓存计算值的方式使用计算值。默认:false
。
¥Forbids the direct access of any unobserved computed value from outside an action or reaction.
This guarantees you aren't using computed values in a way where MobX won't cache them. Default: false
.
在下面的示例中,MobX 不会将计算值缓存在第一个代码块中,而是将结果缓存在第二个和第三个代码块中:
¥In the following example, MobX won't cache the computed value in the first code block, but will cache the result in the second and third block:
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
¥Warns about any unobserved observable access.
Use this if you want to check whether you are using observables without a "MobX context".
This is a great way to find any missing observer
wrappers, for example in React components. But it will find missing actions as well. Default: false
configure({ observableRequiresReaction: true })
注意:在用 observer
封装的组件上使用 propTypes 可能会触发此规则的误报。
¥Note: using propTypes on components that are wrapped with observer
might trigger false positives for this rule.
reactionRequiresObservable: boolean
当在未访问任何可观察量的情况下创建反应(例如 autorun
)时发出警告。使用它来检查你是否不必要地使用 observer
封装 React 组件,使用 action
封装函数,或者查找你只是忘记使某些数据结构或属性可观察的情况。默认:false
¥Warns when a reaction (e.g. autorun
) is created without accessing any observables.
Use this to check whether you are unnecessarily wrapping React components with observer
, wrapping functions with action
, or find cases where you simply forgot to make some data structures or properties observable. Default: false
configure({ reactionRequiresObservable: true })
disableErrorBoundaries: boolean
默认情况下,MobX 将捕获并重新抛出代码中发生的异常,以确保一个异常中的反应不会阻止其他可能不相关的反应的计划执行。这意味着异常不会传播回原始引发代码,因此你将无法使用 try/catch 捕获它们。
¥By default, MobX will catch and re-throw exceptions happening in your code to make sure that a reaction in one exception does not prevent the scheduled execution of other, possibly unrelated, reactions. This means exceptions are not propagated back to the original causing code and therefore you won't be able to catch them using try/catch.
通过禁用错误边界,异常可以转义推导。这可能会简化调试,但可能会使 MobX 以及扩展的应用处于不可恢复的损坏状态。默认:false
。
¥By disabling error boundaries, exceptions can escape derivations. This might ease debugging, but might leave MobX and by extension your application in an unrecoverable broken state. Default: false
.
此选项非常适合单元测试,但请记住在每次测试后调用 _resetGlobalState
,例如在 Jest 中使用 afterEach
,例如:
¥This option is great for unit tests, but remember to call _resetGlobalState
after each test, for example by using afterEach
in jest, for example:
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
¥MobX makes some fields non-configurable or non-writable to prevent you from doing things that are not supported or would most likely break your code. However this can also prevent spying/mocking/stubbing in your tests.
configure({ safeDescriptors: false })
disables this safety measure, making everything configurable and writable.
Note it doesn't affect existing observables, only the ones created after it's been configured. Use with caution and only when needed - do not turn this off globally for all tests, otherwise you risk false positives (passing tests with broken code). Default: true
configure({ safeDescriptors: false })
更多配置选项
¥Further configuration options
isolateGlobalState: boolean
当同一环境中存在多个活动的 MobX 实例时,隔离 MobX 的全局状态。当你有一个使用 MobX 的封装库且与使用 MobX 的应用位于同一页面时,这非常有用。当你从库中调用 configure({ isolateGlobalState: true })
时,库内的反应性将保持独立。
¥Isolates the global state of MobX when there are multiple instances of MobX active in the same environment. This is useful when you have an encapsulated library that is using MobX, living in the same page as the app that is using MobX. The reactivity inside the library will remain self-contained when you call configure({ isolateGlobalState: true })
from it.
如果没有此选项,如果多个 MobX 实例处于活动状态,它们的内部状态将被共享。好处是两个实例的可观察量可以一起工作,缺点是 MobX 版本必须匹配。默认:false
¥Without this option, if multiple MobX instances are active, their internal state will be shared. The benefit is that observables from both instances work together, the downside is that the MobX versions have to match. Default: false
configure({ isolateGlobalState: true })
reactionScheduler: (f: () => void) => void
设置一个执行所有 MobX 反应的新函数。默认情况下,reactionScheduler
仅运行 f
反应,没有任何其他行为。这对于基本调试或减慢反应以可视化应用更新非常有用。默认:f => f()
¥Sets a new function that executes all MobX reactions.
By default reactionScheduler
just runs the f
reaction without any other behavior.
This can be useful for basic debugging, or slowing down reactions to visualize application updates. Default: f => f()
configure({
reactionScheduler: (f): void => {
console.log("Running an event after a delay:", f)
setTimeout(f, 100)
}
})