@formily/reactive 响应式内核解读:Formily 为什么重新造一个基于 Proxy 的响应式轮子
前端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的设计动机展开从 MobX 的四个能力缺口出发解释 Formily 为何在表单场景下必须重新实现一套基于 ES Proxy 的响应式编程模型并结合本仓库源码observable.ts、autorun.ts、reaction.ts、batch.ts深入剖析其核心概念与工程实践。读完你将理解 Observable / Reaction / Computed / Batch 四类原语在 Formily 中的定位、与 MobX 的取舍差异以及如何在业务代码中写出高性能且不泄漏内存的响应式逻辑。一、为什么要重新造轮子四个能力缺口formily/reactivepackage.json 中版本为 2.3.7MIT 协议是 Formily 的响应式内核它的核心思想参考了 MobX但又刻意选择了“重新造轮子”。官方文档docs/guide/index.zh-CN.md给出了 4 点直接原因这四点全部指向表单场景下的特殊需求而非单纯的“重复造轮子”MobX 不支持在 action 内部进行依赖收集。表单联动中一个联动逻辑往往在修改多个字段值的同时又要读取其他字段值来计算新值读操作依赖收集与写操作派发更新交织在同一段代码里。若 action 内不能收集依赖联动依赖就无法被正确追踪而这恰是 Formily 联动表达式频繁出现的模式。MobX 的 observable 函数不支持过滤 React Node、moment、Immutable 之类的特殊对象。表单数据中经常混入日期对象moment/dayjs、不可变数据结构、甚至 JSX 片段如自定义渲染节点如果响应式代理把这些对象也深度劫持会产生不必要的开销甚至行为异常。Formily 需要一套可配置的“哪些对象不该被劫持”的策略。MobX 的 observable 函数会自动把函数变成 action。这在表单场景中会带来隐式副作用字段校验、联动处理器等函数一旦被自动包装为 action其内部的批量与不追踪语义就不是开发者显式可控的容易产生难以排查的行为差异。Formily 希望“函数是否是 action”由开发者显式决定。mobx-react-lite 的 observer 不支持 React 并发渲染。随着 React 18 并发渲染Concurrent Rendering成为主流渲染可能被中断、恢复、重放响应式订阅与派发如果与渲染阶段耦合不严会出现订阅泄漏或更新丢失。Formily 面向 React/React Native 的生态要求 observer 语义必须与并发渲染安全兼容。这四点共同指向一个结论通用响应式库在表单这一高频、高耦合的场景里存在结构性约束Formily 需要一把更贴合的“扳手”。1.1 重新造轮子的三个收益官方文档同时明确了自研而非打补丁的三个好处把控性更强可以为 Formily 场景做更深的优化定制。例如在 observable.ts 中observable函数仅一行调用createObservable(null, null, target)即完成深度代理创建同时把box/ref/deep/shallow/computed等注解静态挂载到函数上API 形态完全由自身掌控。不用考虑 MobX 的历史包袱内部实现依赖收集栈ReactionStack、批处理计数等可以按需精简代码更干净。版本风险隔离如果 MobX 出现 Breaking Change 或安全漏洞不会传导到 Formily 及其使用方。二、技术前提强依赖 ES Proxy不支持 IE重新造轮子的底气来自 ES Proxy。从源码看响应式对象通过 Proxy 劫持数据操作来实现“完美拦截”深度 observable 由createObservable递归构建见 internals.ts由 observable.ts 调用对象数据树的构建逻辑集中在 tree.tsmodel与define都依赖buildDataTree来建立可观测结构见 model.ts。因此formily/reactive 不支持 IE 浏览器这是官方文档明确说明的适用前提目标运行环境必须原生支持 Proxy。如果项目需要兼容 IE 11 及以下不应直接使用本包。三、核心概念四类原语虽然介绍文档本身聚焦于“动机”但它的延伸章节docs/guide/concept.zh-CN.md把整个模型抽象为四个概念这里结合源码做纵深解读。3.1 Observable可订阅对象Observable 是响应式模型的地基创建一个可订阅对象在每次操作其属性数据的过程中自动通知订阅者。formily/reactive 通过以下 API 创建 observableAPI语义对应源码observable(target)创建深度 observable 对象深劫持observable.tsobservable.deep深劫持 observable 对象同上注解实现见 annotations/observable.tsobservable.shallow浅劫持 observable 对象annotations/shallow.tsobservable.computed创建缓存计算器annotations/computed.tsobservable.box创建带get/set方法的 observable 对象annotations/box.tsobservable.ref创建引用级 observable 对象不深劫持内部annotations/ref.tsdefine(target, annotations)按注解定义 observable 领域模型model.tsmodel(target)自动领域模型getter 包装为 computed函数包装为 action其余数据深劫持model.ts从源码看model的实现非常直白遍历对象键用Object.getOwnPropertyDescriptor判断是否存在 getter是则标记observable.computed、是否为函数是则标记action其余字段统一标记为observable深劫持最后交给define通过buildDataTree建立数据树model.ts。3.2 Reaction订阅者Reaction 是“订阅者”角色它接收一个 tracker 函数执行时对 observable 属性的读操作进行依赖收集并建立绑定当该属性在其他地方发生写操作时触发 tracker 重复执行。整个订阅→派发是一个封闭的循环状态机每次执行都会重新收集依赖。对应的三个 APIautorun(tracker)自动执行的响应器创建后立即执行一次返回dispose函数。源码中它维护_memos与_effects两套队列用于 memo/effect 的缓存autorun.ts。reaction(tracker, subscriber, options)支持脏检查dirty check的响应器只有当 tracker 返回值oldValue ! currentValue或自定义equals判定不等时才触发 subscriber还支持fireImmediately选项autorun.ts。Tracker手动依赖追踪器track方法由用户手动触发构造时可注入自定义scheduler其默认调度行为是“边界为 0 时自动 dispose”tracker.ts。重要提醒来自官方文档一旦不再订阅 reaction一定要手动调用其返回的 dispose 函数否则会造成内存泄漏。在 React 组件中使用时通常配合useEffect的清理函数或在组件卸载时调用。3.3 Computed可缓存计算结果的 Reaction一句话概括computed 是一个可以缓存计算结果的 Reaction。只要 computed 函数内部依赖的 observable 数据不变就一直读取缓存结果依赖变化才重新计算。因此官方文档对 computed 有一个硬性要求computed 函数必须是纯函数内部依赖只能是 observable 数据或外部常量。如果引用了非 observable 的外部变量该变量变化时 computed 不会重新计算——这是缓存语义决定的不是 bug。3.4 Batch合并更新减少派发次数因为基于 Proxy 劫持任何一个原子操作都会触发 Reaction 执行。例如import { observable, autorun } from formily/reactive const obs observable({}) const handler () { obs.aa 123 obs.bb 321 } autorun(() { console.log(obs.aa, obs.bb) }) handler()autorun默认执行一次打印加上obs.aa赋值、obs.bb赋值各触发一次共打印 3 次原子操作越多触发次数越多。使用batch将更新合并后只执行 2 次import { observable, autorun, batch } from formily/reactive const obs observable({}) const handler () { obs.aa 123 obs.bb 321 } autorun(() { console.log(obs.aa, obs.bb) }) batch(() { handler() })源码层面batch是createBoundaryAnnotation(batchStart, batchEnd)的产物并额外提供batch.scope作用域批量与batch.endpoint批量结束后回调注册见 batch.ts。3.5 action高阶批量包装除了显式batch还可以用action做高阶包装把“批量 不追踪”的语义固化到函数上import { observable, autorun, action } from formily/reactive const obs observable({}) const handler action.bound(() { obs.aa 123 obs.bb 321 }) autorun(() { console.log(obs.aa, obs.bb) }) handler()最终执行次数同样是 2 次且 handler 内部操作再多也保持 2 次。源码中action由createBoundaryAnnotation同时开启batchStart untrackStart结束时执行untrackEnd batchEndaction.ts并支持action.scope。四、最佳实践四条工程守则官方文档docs/guide/best-practice.zh-CN.md给出了 4 条可落地的实践建议分别对应性能与内存两大主题尽量少用observable/observable.deep深度包装非不得已时优先observable.ref/observable.shallow性能更好。深劫持需要递归构建数据树并给每个层级挂代理浅代理与引用级代理的构建和读写开销都更小。领域模型中多用 computed 计算属性它可以智能缓存计算结果避免重复派生计算。批量操作不是必须的但尽量多用batch模式减少 Reaction 的执行次数降低无效计算。使用autorun/reaction时务必调用 dispose即调用函数返回的二阶函数否则会内存泄漏。这与 autorun.ts 中返回disposeBindingReactions disposeEffects清理函数的实现一一对应。五、源码地图如何继续深入formily/reactive的公开 API 集中在 src/index.ts统一导出了batch、action、untracked、observable、model、autorun、tracker、observe、externals与类型定义是阅读全部导出面的入口。建议按以下顺序深入依赖收集与派发核心reaction.tsReactionStack、batchStart/batchEnd、disposeBindingReactions等注解实现src/annotations6 个注解文件对应box/ref/deep/shallow/computed/observable领域模型model.ts数据树构建tree.ts测试佐证src/tests共 16 个测试文件覆盖 observable、autorun、batch 等行为可运行npm test或在该目录下查阅具体用例验证本文所述行为。整套内核被上层 packages/react、packages/vue、packages/element、packages/next、packages/antd 等 UI 库复用并进一步支撑 packages/core 的表单模型与 packages/json-schema 的 Schema 驱动能力——理解本包就等于拿到了阅读 Formily 全链路源码的钥匙。结语formily/reactive是一次“场景驱动的自研”因为表单联动需要在 action 内收集依赖、需要过滤特殊对象、需要显式控制函数语义、需要兼容 React 并发渲染所以 Formily 基于 Proxy 重写了整个响应式内核换来更强的可控性、更干净的代码与版本风险隔离。在使用层面只要守住“浅代理优先、多用 computed 与 batch、及时 dispose”三条原则就能在表单应用中稳定获得预期的高性能表现。赞分享前端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 核心架构深度解析基于 formily/reactive 领域模型的响应式表单内核Formily 核心架构深度解析基于 formily/reactive 领域模型的响应式表单内核 导读 本文围绕 packages/core/docs/gu前端UI组件Formily 核心架构解析基于 formily/reactive 响应式领域模型的设计原理Formily 核心架构解析基于 formily/reactive 响应式领域模型的设计原理 导读 本文围绕 packages/core/docs/guid前端UI组件Formily 响应式渲染formily/reactive-react 的 observer 与 Observer 使用指南Formily 响应式渲染formily/reactive react 的 observer 与 Observer 使用指南 本文是 Formily 官方文前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

99.6%覆盖率是如何炼成的:mime4cj双层测试架构完整解析

99.6%覆盖率是如何炼成的:mime4cj双层测试架构完整解析

99.6%覆盖率是如何炼成的:mime4cj双层测试架构完整解析 【免费下载链接】mime4cj MIME格式解析库 项目地址: https://gitcode.com/Cangjie-TPC/mime4cj 🎯 mime4cj 是一款面向**仓颉语言(Cangjie)**的 MIME格式解析库&…

2026/9/24 15:59:08 阅读更多 →
语言模型也能当Harness?AX的框架无关设计哲学解读

语言模型也能当Harness?AX的框架无关设计哲学解读

语言模型也能当Harness?AX的框架无关设计哲学解读 【免费下载链接】ax Googles open agentic orchestration runtime 项目地址: https://gitcode.com/GitHub_Trending/ax11/ax AX(Agent Executor)是 Google 开源的 agentic 编排运行时…

2026/9/24 15:59:08 阅读更多 →
codewhale web 浏览器客户端教程:把 CodeWhale 终端 Agent 装进浏览器的完整指南

codewhale web 浏览器客户端教程:把 CodeWhale 终端 Agent 装进浏览器的完整指南

codewhale web 浏览器客户端教程:把 CodeWhale 终端 Agent 装进浏览器的完整指南 【免费下载链接】Codewhale Open-source coding agent for your terminal, built in Rust and on a journey of continuous community improvement. Issues and PRs welcome. 项目地…

2026/9/24 15:59:08 阅读更多 →

最新新闻

AWS SDK for C++ 跨服务示例全解析:从 Aurora Serverless 任务追踪器到 SNS/SQS 发布订阅

AWS SDK for C++ 跨服务示例全解析:从 Aurora Serverless 任务追踪器到 SNS/SQS 发布订阅

示例工程教程后端 【免费下载链接】aws-doc-sdk-examples Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below. 项目地…

2026/9/24 16:37:44 阅读更多 →
关于电缆标签

关于电缆标签

1.电缆按照树结构分 2,隐藏电缆高层代号3.页—页宏–插入 导入宏文件 线缆标签名称自动生成 线缆标签不重复

2026/9/24 16:37:44 阅读更多 →
PHPStan 错误标识符 requireImplements.deprecatedClass 详解:`@phpstan-require-implements` 引用已废弃类时的检测与修复

PHPStan 错误标识符 requireImplements.deprecatedClass 详解:`@phpstan-require-implements` 引用已废弃类时的检测与修复

PHPStan 错误标识符 requireImplements.deprecatedClass 详解:phpstan-require-implements 引用已废弃类时的检测与修复 【免费下载链接】phpstan PHP Static Analysis Tool - discover bugs in your code without running it! 项目地址: https://gitcode.com/gh_…

2026/9/24 16:37:43 阅读更多 →
优秀的项目经理,从来不靠记忆力跟进项目进度

优秀的项目经理,从来不靠记忆力跟进项目进度

很多管理者每天极度内耗: 靠着大脑死记几十项任务、记每个节点工期、记谁的工作没完成、记哪里存在卡点。 真正资深、能同时掌控多个项目的项目经理,往往一点都不忙乱。不是他们记忆力更强、精力更充沛,而是他们早就戒掉了靠记忆管理项目的低…

2026/9/24 16:37:43 阅读更多 →
如何自动识别文件编码?chardet4cj 字符编码检测库新手完全入门指南

如何自动识别文件编码?chardet4cj 字符编码检测库新手完全入门指南

如何自动识别文件编码?chardet4cj 字符编码检测库新手完全入门指南 【免费下载链接】chardet4cj 一个用于检测常用文本编码的库 项目地址: https://gitcode.com/Cangjie-TPC/chardet4cj 打开一个来路不明的文本文件,却看到满屏乱码?这…

2026/9/24 16:37:43 阅读更多 →
如何快速接入支付宝支付?alipay_sdk_cj仓颉原生SDK完全指南

如何快速接入支付宝支付?alipay_sdk_cj仓颉原生SDK完全指南

如何快速接入支付宝支付?alipay_sdk_cj仓颉原生SDK完全指南 【免费下载链接】alipay_sdk_cj AliPay Sdk for 仓颉 支付宝接口后端sdk,方便cangjie开发者快速接入支付宝的支付接口(目前只支持最广泛使用的商户直接接入模式,只支持最…

2026/9/24 16:36:43 阅读更多 →

日新闻

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为…

2026/9/24 0:00:19 阅读更多 →
单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

单细胞注释实战:基于Scanpy的标记基因与参考映射流程解析

简介:一份基于单细胞RNA测序数据的细胞类型注释算法研究Python毕业设计源码,针对计算机相关专业正在做毕设或需要项目实战的学习者,可用于课程设计与期末大作业。项目代码完整、经导师指导评审通过,可直接运行,覆盖数据…

2026/9/24 0:00:19 阅读更多 →
C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

C#源生成器实战:用增量生成器替代反射,告别AOT崩溃

第一次在项目里被反射卡住,是在一个老旧的WinForms模块里:几十个类依赖PropertyChanged通知,运行时反射读属性、发通知,每次启动慢半拍不说,一上.NET Native/AOT裁剪模式几乎全面崩盘。后来我把这段逻辑全部改成C#源生…

2026/9/24 0:00:19 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →