Formily 2.x 业务逻辑管理指南:effects 与 reactions 的定位、选择与最佳实践

发布时间:2026/9/23 3:07:28

Formily 2.x 业务逻辑管理指南:effects 与 reactions 的定位、选择与最佳实践 Formily 2.x 业务逻辑管理指南effects 与 reactions 的定位、选择与最佳实践【免费下载链接】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/formilyFormily 2.x 提供了多种描述表单业务逻辑的方式——字段局部的reactions、Schema 协议中的x-reactions结构化与函数态两种写法以及从 1.x 继承并重构的effects。本文以「管理业务逻辑」为主题系统讲解这几种逻辑承载形态各自的定位、适用场景、优先级与底层实现原理并结合源码给出可直接落地的配置示例帮助你为不同复杂度的表单选择正确的逻辑管理策略。一、Formily 2.x 描述逻辑的三种方式在纯 JSX源码模式与 SchemaJSON Schema模式下Formily 2.x 描述逻辑的能力可以总结为以下三条路径纯 JSX 模式下的effects或reactions属性直接在字段组件上声明reactions或在createForm({ effects() {...} })中声明effectsSchema 模式下的effects或结构化x-reactions属性把联动逻辑写成 JSON 可序列化的结构化对象Schema 模式下的effects或函数态x-reactions属性把联动逻辑写成可执行的函数表达式甚至直接引用注册在上下文作用域中的通用函数。既然有这么多描述逻辑的方式就必须先理解effects与reactions的本质定位才能在具体场景中做出正确选择。二、reactions字段属性上的局部响应器reactions是挂在具体字段属性上的响应器。它的核心特点是函数内部依赖了哪些响应式数据当这些数据变化时函数就会重复执行。因此它简单直接、容易理解非常契合字段级的小逻辑/* eslint-disable */ Field nameA reactions{(field) { /**具体逻辑实现**/ }} /从源码层面看reactions的响应式执行机制位于 packages/core/src/shared/internals.ts 的createReactionsexport const createReactions (field: GeneralField) { const reactions toArr(field.props.reactions) field.form.addEffects(field, () { reactions.forEach((reaction) { if (isFn(reaction)) { field.disposers.push( autorun( batch.scope.bound(() { if (field.destroyed) return reaction(field) }) ) ) } }) }) }可以看到reactions会被统一收敛为数组toArr且支持函数与结构化对象两种形态每个函数态reaction都被包进一个autorun响应式作用域这正是「基于函数内依赖的数据变化重复执行」的底层来源执行被包裹在batch.scope.bound中避免频繁触发多余的重渲染字段销毁后field.destroyed不再执行避免泄漏。三、effects副作用隔离与批量处理逻辑模型effects是 Formily 用于实现副作用隔离的逻辑管理模型。它最大的优势体现在两类场景字段数量超多时把逻辑从视图层抽离到统一位置让视图代码更易维护批量处理字段例如 A、B、C 三个字段声明了完全相同的x-reactions逻辑在effects中只需要写一次onFieldReact(*(A,B,C), (field) { //...逻辑 })其中*(A,B,C)是 FormPath 通配匹配语法可一次命中多个字段。使用effects的另一个好处是可复用逻辑插件化可以把一系列通用逻辑封装成可插拔的插件同时还能做全局监控之类的事情例如统一监听所有字段的值变化、校验状态等。effects 的源码实现以onFieldReact为例其实现位于 packages/core/src/effects/onFieldEffects.tsexport function onFieldReact( pattern: FormPathPattern, callback?: (field: GeneralField, form: Form) void ) { onFieldInit(pattern, (field, form) { field.disposers.push( autorun(() { if (isFn(callback)) callback(field, form) }) ) }) }onFieldReact内部先调用onFieldInit完成字段初始化若字段尚未挂载则等待其出现再把回调包进autorun并挂到field.disposers上因此onFieldReact是响应式的——回调中访问的字段状态发生变化时回调会自动重跑这与局部reactions的响应式语义完全一致只是把作用范围从「单个字段」扩展到了「匹配 pattern 的一批字段」。onFieldReact同文件还提供了一批基于生命周期事件的副作用钩子如onFieldValueChange、onFieldInputValueChange、onFieldInit、onFieldMount、onFieldUnmount、onFieldValidateStart、onFieldSubmit、onFieldReset、onFieldLoading等它们由createFieldEffect统一生成每个钩子都会做FormPath.parse(pattern).matchAliasGroup(field.address, field.path)的路径匹配并包在batch中执行回调见同文件 L13-L32。相关生命周期类型定义在 packages/core/src/types.ts 中reactions支持FieldReaction[] | FieldReaction。四、是否还需要局部定义逻辑并不是。选择effects还是reactions本质是维护成本与表达成本的权衡字段数量很多、逻辑复杂视图层满屏reactions会很难阅读与维护把逻辑抽离到effects统一管理是更好的策略字段数量很少、逻辑简单直接在字段属性上写reactions清晰明了没有必要绕道effects。因此局部逻辑能力必须保留reactions与effects不是互斥方案而是互补方案。五、Schema 模式结构化 x-reactions由于 JSON Schema 可以被配置化系统消费例如低代码平台的配置界面我们需要在配置界面上对某个具体字段做逻辑配置因此必须支持结构化描述逻辑的能力。结构化x-reactions的典型写法如下{ x-reactions: { dependencies: [aa], fulfill: { state: { visible: {{$deps[0] 123}} } } } }关键字段说明dependencies声明本字段依赖的其他字段路径编译期会收集为$deps数组供表达式引用fulfill.state满足条件默认恒为 true时对目标字段状态的批量赋值赋值表达式支持{{...}}模板插值$deps[0]取dependencies中第一个依赖字段的当前值该示例表达的是当依赖字段aa的值等于字符串123时本字段visible置为true。这类结构化写法可以解决大部分配置场景的联动需求因为它纯粹由数据驱动、可序列化、可持久化到后端。结构化 x-reactions 的编译链路结构化x-reactions的编译入口位于 packages/json-schema/src/transformer.ts 的getUserReactionsconst reactions: SchemaReaction[] toArr(schema[x-reactions]) return reactions.map((unCompiled) { return (field: Field) { const baseScope getBaseScope(field, options) const reaction shallowCompile(unCompiled, baseScope) if (!reaction) return if (isFn(reaction)) { return reaction(field, baseScope) } const { when, fulfill, otherwise, target, effects } reaction const run () { const $deps getDependencies(field, reaction.dependencies) ... const request condition ? fulfill : otherwise ... } if (target) { reaction.effects effects?.length ? effects : DefaultFieldEffects } if (reaction.effects) { autorun.memo(() { untracked(() { each(reaction.effects, (type) { if (FieldEffects[type]) { FieldEffectstype } }) }) }, []) } else { run() } } })从中可以读出几个重要事实x-reactions会被toArr收敛成数组每个字段可以同时挂多条 reaction因此也支持数组形态的x-reactions如果编译结果是函数则直接以函数态调用否则解构出when / fulfill / otherwise / target / effects结构化字段dependencies通过getDependencies收集为$deps注入表达式作用域未显式声明target时作用于字段自身声明了target则默认绑定DefaultFieldEffects生效时机即在字段初始化和值变化时执行联动最终Schema 的x-reactions会在 transformFieldProps 中被转换为字段的reactions属性基础 reaction 用户 reactions 拼接从而与纯 JSX 模式共用同一套字段响应机制——这正是「Schema 协议最终编译为字段属性」的架构设计。Schema 表达式作用域结构化表达式中可引用的作用域变量在 transformer.ts 中注入主要包括$self当前字段$form表单实例$deps/$dependencies依赖字段值数组$target目标字段target指定$values表单值$props、$observable、$effect、$memo、$index以及options.scope中注册的自定义变量如customFunction。六、Schema 模式函数态 x-reactions当联动过程存在异步、逻辑非常复杂、或者存在大量数据处理时结构化写法难以承载此时只能开放函数态描述的能力{ x-reactions: {{(field){/**具体逻辑实现**/}}} }这种写法已经很接近低代码配置的形态——把一段可执行函数直接以字符串模板的形式放进 Schema。更进一步还可以在上下文作用域中注册一系列通用逻辑函数然后在 Schema 中按名称引用{ x-reactions: {{customFunction}} }其中customFunction通过createSchemaField({ scope: { customFunction } })React 侧或createForm({ effects })配合作用域注入。这种方式让配置系统可以复用沉淀下来的通用逻辑函数实现「低代码 可编程」的结合。异步场景的完整示例可以参考联动逻辑文档中的 异步联动 一节Effects 方案通过setTimeoutfield.loading模拟异步Schema 方案则通过scope.asyncVisible函数配合x-reactions.fulfill.run执行。七、业务逻辑管理的优先级总结综合以上分析Formily 2.x 管理业务逻辑的方式有以下优先级建议纯源码模式字段数量庞大、逻辑复杂优先选择在effects中定义逻辑字段数量少、逻辑简单优先选择在reactions中定义逻辑。Schema 模式不存在异步逻辑优先选择结构化x-reactions定义逻辑存在异步逻辑或大量计算优先选择函数态x-reactions定义逻辑。八、相关文档与进一步阅读联动逻辑的完整实战示例一对一、一对多、依赖、链式、循环、自身、异步联动均有 Effects 与 SchemaReactions 双版本实现docs/guide/advanced/linkages.mdformily/core中 effects 钩子的完整能力onFieldReact、onFieldValueChange、onFieldInit等可查阅 packages/core/src/effects/onFieldEffects.ts其生命周期类型定义在 packages/core/src/types.ts响应式执行机制autorun/reaction在 packages/core/src/shared/internals.ts 与 packages/reactive 包中实现Schema 编译与x-reactions转换链路见 packages/json-schema/src/transformer.ts。【免费下载链接】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创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/23 3:07:28

JsonSurfer实战:流式解析超大JSON,内存占用降低10倍

去年在做日志清洗任务时,碰到一个特别头疼的场景:线上导出一份接近 2GB 的 JSON 日志文件,里面记录了用户一整天的行为明细。用以前惯用的方式JsonNode整体加载解析,程序刚跑起来内存就飙到 6GB 多,几分钟后直接 OOM。…

2026/9/23 3:07:28

自编码器图像去噪实战:从原理到PyTorch实现与调优

简介:基于Python深度学习的自编码器图像去噪项目,是一套面向毕业设计、期末大作业与课程设计的高分参考实现,围绕图像去噪任务提供DAE、VAE、DCAE三种自编码器变体,适合已有Python基础、希望快速上手深度学习的中级学习者&#xf…

2026/9/23 3:02:28

u5滤镜下载保姆级教程:3步搞定面试原理难题

u5滤镜下载保姆级教程:3步搞定面试原理难题 面试被问原理答不上来,那种大脑一片空白的感觉真的窒息。 很多后端或前端同学在准备技术栈时,容易陷入“只会调包,不懂底层”的陷阱。…

2026/9/23 3:57:30

代码世界模型:从编码智能体到理解世界的数字大脑

直接说结论:代码世界模型这个提法,乍一听很像概念炒作,但你把它拆开看,其实是把“让大模型通过写代码来理解世界”这个路线推到极致的一种尝试。我最近半年一直在折腾编码智能体相关的项目,从最早的代码补全&#xff0…

2026/9/23 3:57:30

cook怎么读新手避坑指南3个核心原理

cook怎么读新手避坑指南3个核心原理 看了一堆教程还是不会写项目?别急,问题可能出在你对基础概念的理解偏差上。很多新手在接触编程时,会被各种术语和发音困扰,比如“cook”这个词,明明是个英文单词,但在特定技术语境下却有着完全不同的含义。…

2026/9/23 3:57:30

AI工业视觉检测:如何把老师傅经验翻译成算法并接入工控系统

质检线上的老师傅,往往是整个车间里最“贵”的人。他拿放大镜看一个冲压件,三秒钟就能告诉你毛刺在哪个位置、压伤的痕迹是旧伤还是新伤、这个料要不要返工。这种基于十几年肌肉记忆的“手感”,恰恰是最难被量化、也最难被复制的东西。我们做…

2026/9/23 3:57:30

10年开发避坑:tom.365源码解析面试必问3大雷区

10年开发避坑:tom.365源码解析面试必问3大雷区 官方文档太长抓不住重点?别慌。 面试必问的tom.365源码解析,90%的人死在配置细节上。 今天把踩过的坑全掏出来,保你面试不挂科。 现象与报错:为什么你的tom.365跑不起来…

2026/9/23 3:57:30

六种主流论文引用标注方法全解析与智能工具实操指南

在学术写作这件事上,我见过太多人把80%的时间花在正文排版上,最后却被参考文献格式一击致命。投稿系统里的“格式不符合期刊要求”通常看起来轻飘飘,实际上直接意味着稿件被打回,严重一点连送审机会都没有。引用标注从来不是一件“…

2026/9/23 3:52:30

猫眼电影网实战:3步搞定环境配置与性能优化

猫眼电影网实战:3步搞定环境配置与性能优化 别问为什么,问就是配置环境就卡半天。刚想跑个爬虫或者做个简单的数据可视化,依赖包装到一半报错,Node版本不对,Python环境冲突,折腾两小时,代码还没写一行。更头疼的是,好不容易跑通了,页面加…

2026/9/22 10:02:42

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/22 9:07:39

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/23 0:01:54

3个实战技巧搞定形式英语:从看教程到跑通性能优化

3个实战技巧搞定形式英语:从看教程到跑通性能优化 看了一堆教程还是不会写项目?别慌,这种“眼高手低”的困境在开发者圈子里太常见了。很多人以为卡点在语法,其实真正拦路虎是缺乏将知识点串联成完整链路的能力。今天咱们不聊虚的,直接拿【形式英语】这…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码