首页/新闻资讯/正文详情

@formily/reactive 响应式内核解读:Formily 为什么重新造一个基于 Proxy 的响应式轮子

发布时间:2026/9/24 15:58:56 来源:云帆数科 栏目:资讯中心
@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:58:56

algorithm-base 仓库题解:LeetCode 560 和为 K 的子数组——从暴力枚举到前缀和 + HashMap 的完整推导
algorithm-base 仓库题解:LeetCode 560 和为 K 的子数组——从暴力枚举到前缀和 + HashMap 的完整推导

文档教程知识库 【免费下载链接】algorithm-base 一位酷爱做饭的程序员,立志用动画将算法说的通俗易懂。我的面试网站 www.chengxuchu.com 项目地址: https://gitcode.com/gh_mirrors/al/algorithm-base 点击查看 免费下载 导读 本文讲解 LeetCode 560… · 2026/9/24 15:58:44

自研充电桩系统充电桩小程序:稳定兼容+全功能闭环
自研充电桩系统充电桩小程序:稳定兼容+全功能闭环

博主介绍: 所有项目都配有从入门到精通的安装教程,可二开,提供核心代码讲解,项目指导。 项目配有对应开发文档、解析等 项目都录了发布和功能操作演示视频;项目的界面和功能都可以定制,包安装运行&#xff… · 2026/9/24 15:58:32

shadcn-vue registry-item.json 完整规范:自定义组件注册表条目字段详解与实战指南
shadcn-vue registry-item.json 完整规范:自定义组件注册表条目字段详解与实战指南

UI组件前端 【免费下载链接】shadcn-vue Vue port of shadcn-ui 项目地址: https://gitcode.com/gh_mirrors/sh/shadcn-vue 点击查看 免费下载 导读 registry-item.json 是 shadcn-vue 组件注册表(registry)生态的核心规范文件,… · 2026/9/24 16:34:05

大麦抢票教程:3步配好抢票自动化脚本,如何把成功率拉满
大麦抢票教程:3步配好抢票自动化脚本,如何把成功率拉满

大麦抢票教程:3步配好抢票自动化脚本,如何把成功率拉满 【免费下载链接】ticket-purchase 大麦自动抢票,支持人员、城市、日期场次、价格选择 项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase 开票一秒&#xff0c… · 2026/9/24 16:33:58

西安24小时自助健身房解决方案:技术架构与实战部署指南
西安24小时自助健身房解决方案:技术架构与实战部署指南

西安24小时自助健身房解决方案:技术架构与实战部署指南 1. 场景概述与核心需求分析 西安作为西北地区的中心城市,健身行业正在经历从“传统人工值守”向“无人化、智能化”的转型。24小时自助健身房的核心痛点在于:如何在无店员值守场景下实现… · 2026/9/24 16:33:52

RE2 正则表达式库实战指南:安全优先的线性时间匹配引擎及其 C++ API 与安装部署
RE2 正则表达式库实战指南:安全优先的线性时间匹配引擎及其 C++ API 与安装部署

RE2 正则表达式库实战指南:安全优先的线性时间匹配引擎及其 C API 与安装部署 【免费下载链接】re2 RE2 is a fast, safe, thread-friendly alternative to backtracking regular expression engines like those used in PCRE, Perl, and Python. It is a C library… · 2026/9/24 16:33:52

轻量级离线翻译:无网也能秒翻
轻量级离线翻译:无网也能秒翻

轻量级离线翻译:无网也能秒翻 【免费下载链接】argos-translate Open-source offline translation library written in Python 项目地址: https://gitcode.com/GitHub_Trending/ar/argos-translate 出差住酒店,Wi-Fi 一断,手机里的在线… · 2026/9/24 16:33:52

Yii2 别名(Aliases)完全指南:从 `@` 符号到路径/URL 解析的底层机制
Yii2 别名(Aliases)完全指南:从 `@` 符号到路径/URL 解析的底层机制

后端Web框架 【免费下载链接】yii2 Yii 2: The Fast, Secure and Professional PHP Framework 项目地址: https://gitcode.com/gh_mirrors/yi/yii2 点击查看 免费下载 别名(Aliases)是 Yii 2 框架中表示文件路径和 URL 的轻量级符号机制&… · 2026/9/24 16:33:39

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

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

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码