
MobX 7 迁移实战React 绑定精简、Stage 3 装饰器与命名空间 API 替换【免费下载链接】mobxSimple, scalable state management.项目地址: https://gitcode.com/gh_mirrors/mo/mobxMobX 7 定位为一次以“清理”为主的发布对绝大多数已经按 MobX 6 惯用方式编写的应用而言升级所需的改动非常有限。本文基于仓库中的迁移文档 migrating-from-6-to-7.md 与 MobX 源码逐节展开React 绑定mobx-react-lite/mobx-react的 API 收缩、Stage 3 装饰器的切换方式、命名空间 API如observable.ref、comparer.structural到命名导出如observableRef、compareStructural的替换、Proxy 成为硬性依赖后的配置清理以及trace、Provider/inject的移除与替代方案。读完本文你可以按清单完成从 MobX 6 到 MobX 7 的升级并理解每项改动在源码中的落点。升级定位一次清理型发布迁移文档开宗明义MobX 7 主要是 a cleanup release清理性发布。这意味着它没有引入新的响应式模型而是移除历史包袱、收缩公开 API 面。因此升级工作集中在四处React 绑定包的 API 精简移除useLocalStore、useAsObservableSource、inject/Provider等装饰器从 legacyStage 2/legacy 语法收敛到 Stage 3 语法命名空间 APIobservable.ref这类“点号属性”替换为具名导出以改善 tree-shakingProxy 成为必需运行环境traceAPI 被移除。更新 React 绑定绑定包继续维持拆分结构MobX 7 保持 React 绑定拆分为两个包mobx-react-lite面向函数组件支持forwardRefmobx-react是mobx-react-lite的薄封装thin wrapper额外支持类组件与observer类装饰器。两个包均要求React 18 或更高版本。从源码可以验证这一“薄封装”结构。mobx-react-lite 入口 的公开导出只有export { isUsingStaticRendering, enableStaticRendering } from ./staticRendering export { observer } from ./observer export { Observer } from ./ObserverComponent export { useLocalObservable } from ./useLocalObservable export { observerFinalizationRegistry as _observerFinalizationRegistry } export const clearTimers observerFinalizationRegistry[finalizeAllImmediately] ?? (() {})而 mobx-react 入口 除observer之外的其余 API 全部直接export ... from mobx-react-lite自身只保留了observer这一个差异化实现export { Observer, isUsingStaticRendering, enableStaticRendering, useLocalObservable, _observerFinalizationRegistry, clearTimers } from mobx-react-lite export { observer } from ./observer其中 mobx-react 的 observer 会先做运行时分支传入的是React.Component/React.PureComponent子类时走makeClassComponentObserver类组件路径否则直接委托给mobx-react-lite的observer函数组件路径。这正是文档所说的“薄封装 类组件装饰器支持”的具体实现。同时它支持作为现代类装饰器使用第二个参数为ClassDecoratorContext时只允许kind class否则抛错。公开 API 面收敛到推荐集合MobX 7 将 React 绑定的公开面收缩到仍然推荐的 5 个 APIobserverObserveruseLocalObservableenableStaticRenderingisUsingStaticRendering以下 API 被移除迁移时按右列方案替换被移除的 API替代方案disposeOnUnmount在componentWillUnmount中释放 reaction或在useEffect中返回清理函数PropTypes使用 TypeScript 或常规的prop-types包useLocalStore改用useLocalObservableuseAsObservableSource将需要的值保存在本地用useEffect从 props 同步useObserver用observer包裹组件或使用Observer组件useStaticRendering改用enableStaticRenderingobserverBatching、isObserverBatched、batchingForReactDom、batchingOptOut、batchingForReactNative直接删除这些导入。React 18 的渲染器会自动处理批处理React Native 的副作用导入也不再需要mobx-react的Provider、inject、MobXProviderContext直接使用React.createContext从源码结构看mobx-react-lite的入口导出列表上文所列已经不包含useLocalStore、useAsObservableSource、useObserver、disposeOnUnmount或任何 batching 相关符号与文档的移除清单完全一致。迁移 legacy 装饰器MobX 7仅支持 Stage 3 装饰器。如果你有两条路径可以选继续保留装饰器切换到 Stage 3 语法或者干脆去掉装饰器、改用显式注解地图。路径一切换到 Stage 3 装饰器语法核心改动三点从被装饰的类中删除makeObservable(this)不再使用时也删除其 import在需要 observable 的字段前加上accessor关键字编译器切换到现代装饰器。迁移前后的 diff 如下-import { makeObservable, observable, computed, action } from mobx import { observable, computed, action } from mobx class Todo { - observable title observable accessor title - observable finished false observable accessor finished false - - constructor() { - makeObservable(this) - } computed get label() { return ${this.finished ? [DONE] : [OPEN]} ${this.title} } action toggle() { this.finished !this.finished } }注意observable accessor title 这一写法Stage 3 中装饰器作用于 getter/setter 而非赋值本身accessor让编译器把字段改写为访问器对从而保证observable能正确拦截读写。computedgetter与action方法则不需要accessor。编译器配置要求TypeScript使用 TypeScript 5 或更高版本并将experimentalDecorators标志禁用或移除Babel使用babel/plugin-proposal-decorators配合当前的 Stage 3 配置。仓库内 Enabling decorators 文档 给出了精确的编译器配置可结合查阅。路径二去掉装饰器使用显式注解地图如果不希望保留装饰器把注解集中传给makeObservable的第二个参数即可这也是 MobX 一贯推荐的显式风格import { makeObservable, observable, computed, action } from mobx class Todo { title finished false constructor() { makeObservable(this, { title: observable, finished: observable, label: computed, toggle: action }) } get label() { return ${this.finished ? [DONE] : [OPEN]} ${this.title} } toggle() { this.finished !this.finished } }两条路径下类的运行行为一致区别仅在于可观测性声明的书写位置——装饰器写在成员旁注解地图集中在构造函数中。替换命名空间 APIMobX 7 将“点号命名空间”形式的注解与比较器属性替换为具名导出动机是让这些值可以被静态分析从而获得更好的 tree-shaking 效果。完整对照表被移除的 API替代 APIobservable.refobservableRefobservable.shallowobservableShallowobservable.deepobservableDeepobservable.structobservableStructcomputed.structcomputedStructaction.boundactionBoundflow.boundflowBoundcomparer.identitycompareIdentitycomparer.defaultcompareDefaultcomparer.structuralcompareStructuralcomparer.shallowcompareShallow注解地图中的替换-import { action, comparer, computed, flow, makeObservable, observable } from mobx import { actionBound, compareStructural, computed, computedStruct, flowBound, makeObservable, observableRef } from mobx makeObservable(this, { - value: observable.ref, value: observableRef, - total: computed.struct, total: computedStruct, - rounded: computed({ equals: comparer.structural }), rounded: computed({ equals: compareStructural }), - save: action.bound, save: actionBound, - load: flow.bound load: flowBound })装饰器中的替换-import { action, comparer, computed, flow, observable } from mobx import { actionBound, compareStructural, computed, computedStruct, flowBound, observableRef } from mobx class Store { - observable.ref accessor value null observableRef accessor value null - computed.struct computedStruct get total() { return { value: this.value } } - computed({ equals: comparer.structural }) computed({ equals: compareStructural }) get rounded() { return { value: Math.round(this.value) } } - action.bound actionBound save() {} - flow.bound flowBound *load() {} }equals显式声明结构比较MobX 7 要求对结构比较显式传递比较函数旧的布尔选项compareStructural: true不再可用-computed(() value, { compareStructural: true }) computed(() value, { equals: compareStructural }) -reaction(() value, effect, { compareStructural: true }) reaction(() value, effect, { equals: compareStructural })源码印证这些具名导出是真实的独立导出在 packages/mobx/src/mobx.ts 的总导出列表中可以看到compareDefault、compareIdentity、compareStructural、compareShallowL42–L45、observableRef/observableShallow/observableDeep/observableStructL79–L82、computedStructL86、actionBoundL102、flowBoundL119均为一等公民的命名导出而comparer、observable.ref这类命名空间属性已不在导出列表中。这些导出的定义也很直接例如 observable.ts 中export const observableRef createObservableDecoratorAnnotation(observableRefAnnotation) export const observableShallow createObservableDecoratorAnnotation(observableShallowAnnotation) export const observableDeep createObservableDecoratorAnnotation(observableAnnotation) export const observableStruct createObservableDecoratorAnnotation(observableStructAnnotation)比较器实现位于 packages/mobx/src/utils/comparer.ts迁移时可以据此确认各比较函数的精确语义export function compareIdentity(a: any, b: any): boolean { return a b } export function compareStructural(a: any, b: any): boolean { return deepEqual(a, b) } export function compareShallow(a: any, b: any): boolean { return deepEqual(a, b, 1) } export const compareDefault Object.is即compareIdentity是严格相等compareStructural是深度相等compareShallow是深度为 1 的相等只比较第一层compareDefault等价于Object.is。替换 API 时如果两者语义不一致需要留意行为差异。Proxy 支持成为硬性要求MobX 7 要求运行时原生支持 Proxy不再内置 ES5 回退实现。相应地有两类旧配置要清理第一从configure调用中移除useProxiesimport { configure } from mobx configure({ enforceActions: observed, - useProxies: ifavailable })第二从observable、observable.object、observable.array的选项中移除{ proxy: false }-const todos observable.object({}, {}, { proxy: false }) const todos observable.object({})源码中有两处直接印证packages/mobx/src/mobx.ts 在开发模式下会检查Symbol、Map、Set、Proxy四个全局是否存在缺失任一则直接抛错MobX requires global ... to be available or polyfilled——这说明 Proxy 已从“可用则用”变成启动前提packages/mobx/src/api/configure.ts 中configure的参数类型只接受enforceActions、computedRequiresReaction、reactionRequiresObservable、observableRequiresReaction、isolateGlobalState、disableErrorBoundaries、safeDescriptors、reactionScheduleruseProxies已不在类型签名中继续传入它在类型层面就无法通过。实际迁移时重点排查目标浏览器/运行环境是否支持 Proxy对确实无法提供 Proxy 的极老环境MobX 7 无法再覆盖需要升级运行环境。trace的移除与调试替代方案traceAPI 在 MobX 7 中已移除。调试响应式依赖时文档推荐以下替代手段getDependencyTree与getObserverTree等 extras APIspyMobX 开发者工具第三方包如mobx-log。文档给出的示例import { autorun, getDependencyTree } from mobx const disposer autorun(() { console.log(message.title) }) console.log(getDependencyTree(disposer))这里getDependencyTree接收 reaction/disposer 作为入口打印出其依赖树可用于回答“这个 autorun 到底读了哪些 observable”这一trace曾经解决的问题。getDependencyTree与getObserverTree都是 mobx.ts 导出列表中的正式 API可直接import使用。替换Provider与injectProvider与inject被移除替代方案是直接使用 React Context。核心原则保持 context 的 value 稳定通过变更 observable store 本身来驱动更新而不是替换 provider 的值。迁移前MobX 6 及更早的 mobx-react 风格import { Provider, inject, observer } from mobx-react // prettier-ignore const UserName inject(userStore)( observer(({ userStore }) span{userStore.name}/span) ) const App ({ userStore }) ( Provider userStore{userStore} UserName / /Provider )迁移后函数组件版本import React, { createContext, useContext } from react import { observer } from mobx-react const RootStoreContext createContext(null) export const RootStoreProvider ({ rootStore, children }) ( RootStoreContext.Provider value{rootStore}{children}/RootStoreContext.Provider ) export const useRootStore () { const store useContext(RootStoreContext) if (!store) { throw new Error(RootStoreProvider is missing) } return store } const UserName observer(() { const { userStore } useRootStore() return span{userStore.name}/span }) const App () ( RootStoreProvider rootStore{{ userStore: new UserStore() }} UserName / /RootStoreProvider )要点说明RootStoreContext只携带 store 实例本身。observer组件通过读取userStore.name这个 observable 属性建立依赖store 内部状态变化时组件才会重渲染——这与旧Provider的语义一致但完全由标准 Context 承载useRootStore自定义 hook 封装了“取不到就抛错”的防御逻辑等价于旧inject中“缺失注入项会警告/报错”的体验因为 context value 是同一个 store 对象且引用稳定context 变更不会触发额外的组件重渲染响应式更新仍由 MobX 的 observer 机制精确驱动。类组件版本则使用static contextType直接消费同一个 contextimport React from react import { observer } from mobx-react const RootStoreContext React.createContext(null) class UserName extends React.Component { static contextType RootStoreContext render() { const { userStore } this.context return span{userStore.name}/span } } const ObservedUserName observer(UserName)迁移检查清单按仓库文档与源码交叉验证升级 MobX 6 → 7 的最小检查清单如下React 绑定确认 React 18全局搜索useLocalStore、useAsObservableSource、useObserver、useStaticRendering、disposeOnUnmount、batching 相关导入与Provider/inject按前文对照表替换装饰器确认只使用 Stage 3 语法accessor字段 无makeObservable(this)或保留注解地图并按 TypeScript 5关闭experimentalDecorators或 Babel Stage 3 插件配置编译器参考 docs/enabling-decorators.md命名空间 API全局替换observable.ref等 11 个属性形式为具名导出compareStructural: true改为equals: compareStructuralProxy 配置删除configure中的useProxies与 observable 选项中的proxy: false确认目标环境支持 Proxy调试将trace调用替换为getDependencyTree/getObserverTree/spy或开发者工具。以上改动均为机械式替换且每一项在 packages/mobx/src、packages/mobx-react-lite/src 与 packages/mobx-react/src 的源码导出面中都有对应印证可按路径继续深入核对实现细节。【免费下载链接】mobxSimple, scalable state management.项目地址: https://gitcode.com/gh_mirrors/mo/mobx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考