前端UI组件【免费下载链接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3项目地址https://gitcode.com/gh_mirrors/fo/formily点击查看免费下载导读raw是formily/reactive响应式核心中一个用于「取回源数据」的底层工具函数。在 Formily 的响应式体系中observable创建的对象是一个 Proxy 代理日常读写都应经由代理完成以保证依赖收集与响应式更新raw则提供了一条绕过代理、直接拿到原始对象的通道。本文基于 raw API 文档中文版见 raw.zh-CN.md结合 formily/reactive 包的源码实现与测试用例详细讲解该 API 的签名、行为边界、内部实现原理以及与toJS、markRaw等关联 API 的异同帮助你在确有需要时安全、正确地使用它。基本描述从 observable 中获取源数据raw的作用非常单一从 observable 对象中获取其源数据原始对象。在 Formily 的响应式架构中observable()会把传入的普通对象包装为 Proxy相关实现见 internals.ts 中的createNormalProxy/createCollectionProxy。此后我们对这个对象的所有读写都会被拦截从而触发依赖收集与副作用通知。而raw返回的正是这个 Proxy 背后未被包装的原始对象。文档同时给出了一个重要提醒这也是本 API 的第一条使用边界注意只能获取当前对象的源数据不包括深层对象属性。即raw(obs)只能拿到obs这一层对应的源对象如果obs的某个属性值是嵌套的 observable 代理如示例中的obs.aa需要单独对obs.aa调用raw才能拿到那一层嵌套对象的源数据。函数签名文档中给出的类型签名如下interface rawT extends object { (target: T): T }入参任意对象target通常是observable()创建的代理对象返回值类型与入参相同实际返回对应的源对象泛型约束为object因为observable体系只针对对象含数组、Map、Set 等集合类型生效。从类型签名可以看出raw是类型安全的传入代理得到的是其源对象类型编译期即可保持一致。基础用例文档给出了最直接的使用示例import { raw, observable } from formily/reactive const obs observable({}) obs.aa { bb: 123 } console.log(raw(obs)) // 输出源对象原始对象 console.log(raw(obs.aa)) // 输出嵌套对象 aa 的源对象这里有两层含义需要展开obs.aa { bb: 123 }这行赋值发生在代理上。由于observable默认是深响应式的obs.aa本身也会被包装为 observable 代理见 internals.ts 中createObservable对嵌套值的递归处理。raw(obs)拿到的是一层源对象raw(obs.aa)拿到的是嵌套对象aa这一层的源对象。两者互不包含——这正是文档中「不包括深层对象属性」的实际体现。源码实现raw 到底做了什么raw的实际实现位于 externals.tsexport const raw T(target: T): T { if (target?.[ObModelSymbol]) return target[ObModelSymbol] return ProxyRaw.get(target as any) || target }该实现依赖 environment.ts 中维护的两个全局映射ProxyRaw: WeakMap记录「代理对象 → 源对象」的映射ObModelSymbolSymbol(ObModelSymbol)用于模型modelAPI场景下标记源对象。因此raw的取值逻辑分为两条路径如果target是model()创建的模型对象带有ObModelSymbol则直接返回target[ObModelSymbol]记录的源对象否则从ProxyRaw这个 WeakMap 中查询代理对应的源对象如果查询不到说明传入的本身就不是 observable 代理则原样返回入参。这意味着raw是一个「安全降级」的函数对任意非代理对象调用raw得到的就是它自己不会报错。这一点非常实用例如在不确定一个值是否被observable包装过时可以直接调用raw而不必先做判断。同时由于ProxyRaw是 WeakMap键为对象弱引用raw的查询不会造成内存泄漏也无需手动清理映射关系。代理创建的对应关系要理解raw为什么有效需要看代理创建时两个映射是如何成对写入的internals.tsconst createNormalProxy (target: any, shallow?: boolean) { const proxy new Proxy(target, baseHandlers) ProxyRaw.set(proxy, target) // 代理 - 源对象 if (shallow) { RawShallowProxy.set(target, proxy) } else { RawProxy.set(target, proxy) } return proxy }ProxyRaw保存「代理 → 源对象」供raw反查RawProxy/RawShallowProxy保存「源对象 → 代理」供内部判断一个源对象是否已有对应代理避免重复包装。两者互为反向索引raw就是利用了其中的ProxyRaw方向。行为边界与注意事项1. 只取当前层不取深层再次强调文档中的核心警告raw只返回当前对象的源数据嵌套的深层对象属性不会被一并还原。若需要递归地把整个对象树还原为纯 JS 数据应使用toJS同为 externals.ts 中导出的 API它会对可观察对象进行递归深拷贝式还原并内置WeakSet防止循环引用导致的死循环。2. 拿到的源对象不再具备响应式能力通过raw拿到的源对象是原始引用直接对它进行读写不会触发任何依赖收集或响应式更新。因此在业务代码中用raw取到的数据只能用于「只读查看」或「一次性导出」等场景不应作为持续读写的数据源。3. 为什么不推荐使用文档明确指出「通常情况下并不推荐使用该 API」。原因在于响应式体系的正确用法是始终经由代理访问数据这样autorun、reaction、observer等才能正确收集依赖。一旦通过raw绕过代理访问很容易破坏依赖收集的完整性造成视图不更新或逻辑时序错乱的隐性 bug。绝大多数「需要原始数据」的场景都可以改用toJS完成。4. 集合类型同样适用raw对Map、Set、WeakMap、WeakSet等集合类型的 observable 代理同样生效createCollectionProxy同样会写入ProxyRaw见 internals.ts。在 collections-map.spec.ts 等测试中可以看到expect(raw(map)).toBeInstanceOf(Map) expect(raw(set)).toBeInstanceOf(Set) expect(raw(weakMap)).toBeInstanceOf(WeakMap) expect(raw(weakSet)).toBeInstanceOf(WeakSet)5. 与 markRaw 的关系raw取回源数据与markRaw标记对象为不可响应是两条互补的边界工具markRaw用于在observable包装时跳过某些对象externals.ts其实现是给目标对象打上RAW_TYPE标记isSupportObservable在判断「对象是否可被包装」时会优先检查RAW_TYPE标记并直接返回falseexternals.ts从而保证被markRaw标记过的对象永远不会成为代理。也就是说markRaw阻止对象被代理raw则是把已被代理的对象还原。两者都服务于「在某些场景下需要访问原始对象」的需求但入口与语义不同。测试用例佐证raw的行为在 packages/reactive/src/tests目录下有充分覆盖除上述集合类型断言外还有大量用例通过raw直接操作源对象来验证响应式行为在 collections-set.spec.ts 中raw(set).add(value)、raw(set).delete(value)、raw(set).clear()直接作用于源 Set在 collections-map.spec.ts 中raw(map).set(key, Hello)、raw(map).delete(key)、raw(map).clear()同理在 collections-weakmap.spec.ts 与 collections-weakset.spec.ts 中也通过raw对 Weak 集合执行增删操作。这些用例一方面验证了raw返回的确实是可直接操作的原生集合实例另一方面也演示了raw的典型测试用法——在测试中绕过代理直接操控源对象以便精确构造或断言底层状态。总结与建议要点说明作用从 observable 代理对象中取回源数据签名rawT extends object(target: T): T返回规则代理 → 源对象模型对象 →ObModelSymbol记录值非代理 → 原样返回深层限制只取当前层源数据不递归还原深层属性推荐替代需要递归还原纯数据时使用toJS使用禁忌拿到的源对象不具备响应式能力不应作为常规读写数据源raw是formily/reactive中一个「存在但默认不应使用」的低层 API。理解它的实现ProxyRaw反查与边界仅当前层、非响应式有助于你深入理解 Formily 响应式体系中「代理 / 源对象」的双层结构而在实际业务中请优先遵循官方建议用toJS或直接经由代理访问数据仅在测试、调试或确需绕过代理的极少数场景下才使用raw。赞分享前端UI组件【免费下载链接】formily Cross Device High Performance Normal Form/Dynamic(JSON Schema) Form/Form Builder -- Support React/React Native/Vue 2/Vue 3项目地址https://gitcode.com/gh_mirrors/fo/formily点击查看免费下载相关推荐formily/reactive hasCollected 详解如何检测依赖是否被收集formily/reactive hasCollected 详解如何检测依赖是否被收集 hasCollected 是 formily/reactive 响前端UI组件Clarity热力图生成指南深度解析用户点击和滚动行为模式Clarity热力图生成指南深度解析用户点击和滚动行为模式 Clarity是一款强大的行为分析库它通过监控DOM变化和用户交互来生成聚合洞察帮助开发者深入人工智能语音音频AI 应用OpenBMBFormily Reactive 的 markObservable强制接管对象的响应式劫持机制Formily Reactive 的 markObservable强制接管对象的响应式劫持机制 导读 markObservable 是 formily/re前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
