re-frame 1.3.0 发布解析:订阅反应上下文告警、enrich 返回 nil 与 reg-sub 语法糖
前端Web框架【免费下载链接】re-frameA ClojureScript framework for building user interfaces, leveraging React项目地址https://gitcode.com/gh_mirrors/re/re-frame点击查看免费下载导读本文围绕 re-frame 1.3.0 版本2022-08-27 定版含 rc1/rc2/rc3 三个候选版本的发布说明展开逐条讲解本次版本的三项核心变更在非反应式上下文reactive context中调用subscribe时给出告警、enrich拦截器允许返回nil以保留原 db、为reg-sub提供:-/:-/:语法糖以及nil作为:fx值由:error降级为:warn日志级别。读完本文你将理解这些变更背后的设计动机掌握对应 API 的正确用法并能从源码层面定位其实现位置。版本背景re-frame 1.3.0 正式发布于 2022-08-27此前经历了 1.3.0-rc32022-03-04、rc22021-12-22与 rc12021-12-20三个候选版本的迭代最终 1.3.0-rc3 被重新打标签re-tag为 1.3.0 正式版。其 Maven 坐标可从 Clojars 页面 获取用于 Maven、tools.deps 与 Leiningen 三种构建方式。版本改动按“Added / Fixed / Changed”分类组织本文依此展开版本时间类型核心内容1.3.0 (final)2022-08-27—1.3.0-rc3 重新打标签为正式版rc32022-03-04Added非反应式上下文调用subscribe时告警enrich允许返回nilrc22021-12-22Fixed修复关于 reg-sub 新增强化的文档rc12021-12-20Added/Changedreg-sub语法糖nil:fx值日志降级为:warn一、非反应式上下文中调用 subscribe 的告警rc3变更内容在 rc3 中re-frame 新增了对“在反应式上下文之外调用subscribe”的场景检测当应用处于 debug 模式且当前并不处于 reagent 渲染函数render function的跟踪上下文中时控制台会打印一条:warn级告警提示订阅可能泄漏。此改动源自 day8/re-frame#740由 dannyfreeman 实现。为什么这是个问题subscribe是有状态的。订阅会创建 reagent reaction 并进入订阅缓存其生命周期依赖 reagent 组件对它的“依赖引用”组件在渲染时调用subscribe会建立引用卸载时移除引用最后一个组件卸载后订阅节点才会被清理。如果在一个没有组件引用的位置调用subscribe就没有任何机制在未来处置dispose这个订阅反复调用会造成内存泄漏。这一点在官方 FAQ 文档 UseASubscriptionInAnEventHandler 中有完整阐述唯一安全的subscribe调用点是 reagent 渲染函数内部。典型的错误场景包括;; 错误DOM 事件回调中调用 subscribereagent/re-frame 无法在此时管理订阅生命周期 (defn my-btn [] [:button {:on-click #(subscribe [:some (gensym)])}]) ;; 错误在事件处理器中调用 subscribe (re-frame.core/reg-event-db :event-id (fn [db v] (let [sub-val (subscribe [:something])] ;; --- 可能的内存泄漏 ....)))re-frame 的事件处理循环运行在 reagent 渲染循环之外的独立上下文中因此事件处理器里的subscribe既无法被正确缓存复用也无法被自动处置。FAQ 中给出的替代方案包括把计算逻辑抽成纯函数在订阅与事件处理器之间共享、在回调中dispatch事件而非订阅、改用re-frame.flow其派生的值可在任何时间任何地点访问或使用re-frame.alpha的自定义生命周期订阅。源码实现告警逻辑位于 src/re_frame/subs.cljc(defn warn-when-not-reactive [] (when (and debug-enabled? (not (reactive?))) (console :warn re-frame: Subscribe was called outside of a reactive context.\n https://day8.github.io/re-frame/FAQs/UseASubscriptionInAnEventHandler/)))reactive?直接委托给 reagent 的reagent.ratom/reactive?见 src/re_frame/interop.cljs它返回当前是否处于 reagent 反应式跟踪环境。warn-when-not-reactive在subscribe的两个 arity 中均被调用src/re_frame/subs.cljc即单参与带动态参数dyn-v的订阅都会先做此检查。需要特别说明的两点仅在 debug 模式下生效debug-enabled?为真时才会告警生产构建advanced 编译不受影响。只告警、不拦截这是一条:warn级提示订阅本身仍会创建。测试 test/re_frame/subs/alpha_test.cljs 通过with-redefs模拟reactive?的不同返回值验证了“已缓存的订阅在非反应式上下文也可用”“reactive生命周期订阅即使脱离组件也会被缓存”等行为——说明在特定场景如订阅已在组件内建立下外部调用并非一定会泄漏。如何正确解决将计算逻辑抽成纯函数订阅与事件处理器共享(defn circle-area [r] (* Math/PI r r)) (def get-areas (comp circle-area :circles)) (reg-sub :areas (fn [db _] (get-areas db))) (reg-event-fx :store-areas (fn [{:keys [db]} _] {:local-store (get-areas db)}))回调中改用dispatch(rf/reg-fx :circle-effect circle-effect!) (re-frame.core/reg-event-fx :clicked-button (fn [{{:keys [circles]} :db :as coeffects} event-v] {:circle-effect circles})) [:input {:type button :value Click me! :on-click #(dispatch [:clicked-button %])}]二、enrich 拦截器允许返回 nilrc3变更内容rc3 放宽了enrich拦截器的约束传给enrich的函数现在可以返回nil此时 re-frame 会保留传入的db作为结果而不是把nil写入 app-db。此改动来自 day8/re-frame#751由 NoahTheDuke 提出。设计与用途enrich是 re-frame 提供的标准拦截器它在:after阶段运行给定的函数ff接收db与event两个参数并返回修改后的db。与只做副作用的after不同enrich期望f对 db 做有意义的加工参与到“派生数据”的流转中。其经典应用是在 todomvc 这类应用中任何 CRUD 事件都可能改变重复项检测的结果若在每个事件处理器里各自实现检测逻辑容易产生微妙的差异而用enrich挂一个“每次全部重算”的纯函数则既保证不错过任何变更又可以独立于 CRUD 事件单独测试这个纯函数。允许返回nil的实际价值在于有时是否应用变更需要在运行时判断而非注册处理器时静态决定。例如(def set-last-update (core/enrich (fn [{db :db} [_ {user :user}]] (when (active-user? user) ;; - 仅当用户处于活跃状态时才更新 ...))))在此之前函数必须保证每个分支都返回 db否则会把nil作为新 db 生效现在只需在不需要修改时返回nilre-frame 会自动回退到传入的 db 值。源码与测试印证实现位于 src/re_frame/std_interceptors.cljc(defn enrich [f] (-interceptor :id :enrich :after (fn enrich-after [context] (let [event (get-coeffect context :event) prev-db (if (contains? (get-effect context) :db) (get-effect context :db) (get-coeffect context :db)) new-db (f prev-db event)] (assoc-effect context :db (or new-db prev-db))))))关键在最后一行(or new-db prev-db)当f返回nil时取prev-db作为新的 db 效果。prev-db的选取也很有讲究——若本次事件已产生:dbeffect则用该新 db 作为f的输入否则回退到 coeffect 中的原始 db。测试 test/re_frame/interceptor_test.cljs 专门覆盖了“f 返回 nil 时使用传入 db”的语义(testing uses given db if f returns nil (let [updater (db-handler-interceptor (fn [db _] (update db :a inc))) ctx (context [] [updater] {:a 1}) enrich-interceptor (enrich (fn [_ _] nil)) result (- ctx ((:before updater)) ((:after enrich-interceptor)))] (is ( {:a 2} (get-effect result :db)))))事件处理器先把{:a 1}更新为{:a 2}随后enrich返回nil最终结果仍为{:a 2}证明 db 未被nil覆盖。完整 API 文档见 src/re_frame/core.cljc其中同样记录了“Iffreturnsnil, thedbvalue passed tofwill be returned instead”的语义。三、reg-sub 语法糖rc1变更内容rc1 引入了“对琐碎 reg-sub 声明trivial reg-sub declarations的语法糖”来自 day8/re-frame#634由 bsboiko 贡献。所谓“琐碎”指的是那些只有一个输入信号、计算函数只需关心信号值而无需关心 query 向量的订阅。语法糖形态在既有:-基础上rc1 让reg-sub的调用形式更加紧凑。官方订阅指南 docs/subscriptions.md 展示了:-的经典用法(reg-sub :id ;; 输入信号 :- [:a] ;; 等价于 (subscribe [:a]) :- [:b 2] ;; 等价于 (subscribe [:b 2]) ;; 计算函数 (fn [[a b] query-v] (calculate-it a b)))在此基础上rc1 补充的语法糖允许省略计算函数中多余的参数。reg-sub的具体解析逻辑在 src/re_frame/subs.cljc 的sugar函数中若第二个到倒数第二个参数为空、或为单个函数、或为query?标识则直接以最后一个参数为计算函数1 参。若倒数第二个参数是:-则把其后的单参函数包装为(fn [db _] (f db))——计算函数只接收信号值忽略 query 向量。若倒数第二个参数是:则包装为(fn [db q] ...)——信号值与 query 向量中的参数都会传入f。:-则与紧随其后的 query 向量组成一对输入信号声明支持多对。实践对比以文档 docs/correcting-a-wrong.md 中的时钟订阅为例原始写法(reg-sub :time-str :- [:time] ;; 这是 signals 函数的语法糖 (fn [t _] (- t .toTimeString (clojure.string/split ) first)))用:-糖可以把计算函数简化为单参形式(reg-sub :time-str :- [:time] :- (fn [t] (- t .toTimeString (clojure.string/split ) first))))在 re-frame 的事件流flow示例 examples/flow/src/re_frame/flow/demo.cljs 以及官方 docs/Flows.md 中也能看到(rf/reg-sub :current-tab :- :tab)、(rf/reg-sub :items :- (comp reverse :items))这类极简写法——当信号值就是整个 db、计算只是 db 的简单映射时甚至可以直接传关键字或函数组合无需显式fn。同时这一糖同样作用于re-frame.alpha的reg :sub见 docs/api-re-frame.alpha-instrumented.md 与 src/re_frame/alpha.cljc 的说明保证新旧订阅 API 的声明体验一致。文档修复rc2rc2 的 Fixed 条目是“修复关于 reg-sub 新增强化的文档”由 eval 等文档中的示例与实际实现保持一致。四、nil 作为 :fx 值日志从 :error 降级为 :warnrc1变更内容rc1 同时修改了事件处理器返回nil作为:fx效果值时的处理方式此前会打印:error级日志现在降为:warn。背景与含义:fx是 re-frame 内建的效果处理器期望值是一个“效果向量”的集合每个元素形如[effect-key effect-value]nil条目会被忽略从而支持条件式地追加效果见 src/re_frame/fx.cljc。因此事件处理器返回{:fx nil}并非致命错误——它等价于“本次不产生任何副作用”。在:fx的 handler 中对非 seq 输入会提示:fx effect expects a seq对无对应 handler 的效果键会提示 no associated handler均为:warn见 src/re_frame/fx.cljc。rc1 将nil值的处理从:error调整为:warn统一了这类“可忽略但不规范”输入的日志等级仍提示开发者注意:fx的期望输入形态但不再把返回nil当作错误对待。这一改动与 rc3 中enrich允许返回nil的精神一脉相承——re-frame 越来越倾向于把“可选/空值”从错误语义中剥离出来只在真正异常时使用:error。五、变更对升级的影响与小结综合 1.3.0 的四个改动对升级者的实践建议如下升级后留意控制台告警若应用在 debug 模式下出现 “Subscribe was called outside of a reactive context” 的:warn说明存在非安全订阅点应按 docs/FAQs/UseASubscriptionInAnEventHandler.md 中的方案重构抽纯函数共享、回调改 dispatch、改用 flow 或 alpha 生命周期订阅。enrich 的新语义让拦截器更易写条件性更新场景如“仅活跃用户才更新”不再需要为每个分支手动返回 db返回nil即可保留原值实现见 src/re_frame/std_interceptors.cljc。reg-sub 声明更简洁单信号 简单映射的订阅可用:-糖一行写出多输入仍使用:-对完整语法解析见 src/re_frame/subs.cljc。:fx返回 nil 不再报错可放心使用条件表达式生成:fx序列(when cond [...] )不必担心nil触发错误日志。相关代码与文档在仓库中的位置汇总订阅告警实现src/re_frame/subs.cljcreactive?委托src/re_frame/interop.cljsenrich拦截器src/re_frame/std_interceptors.cljc、API 文档 src/re_frame/core.cljcenrichnil 语义测试test/re_frame/interceptor_test.cljsreg-sub语法糖解析src/re_frame/subs.cljc:fx效果处理器src/re_frame/fx.cljc订阅相关 FAQdocs/FAQs/UseASubscriptionInAnEventHandler.md订阅语法糖指南docs/subscriptions.md赞分享前端Web框架【免费下载链接】re-frameA ClojureScript framework for building user interfaces, leveraging React项目地址https://gitcode.com/gh_mirrors/re/re-frame点击查看免费下载相关推荐re-frame 订阅外部数据实战指南用 reg-sub-raw 让 app-db 成为唯一的数据入口re frame 订阅外部数据实战指南用 reg sub raw 让 app db 成为唯一的数据入口 re frame 是构建在 React 之上的 C前端Web框架re-frame 中 reg-event-fx 返回 cofx 而非 fx 的陷阱理解 effect 与 coeffect 的本质区别re frame 中 reg event fx 返回 cofx 而非 fx 的陷阱理解 effect 与 coeffect 的本质区别 本文围绕 re fra前端Web框架开源项目的合规边界从PyWxDump事件看技术开发的法治意识开源项目的合规边界从PyWxDump事件看技术开发的法治意识 在开源社区蓬勃发展的今天技术创新与法律合规的平衡成为每个开发者必须面对的现实问题。近期一个曾创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

PRAXIST 产品使用数据隐私声明全解:自愿假名化遥测的架构、边界与合规设计

PRAXIST 产品使用数据隐私声明全解:自愿假名化遥测的架构、边界与合规设计

人工智能AI Agent多智能体Agent 工作流深度研究AI 评测 【免费下载链接】PRAXIST Autonomous research system for measurable, computer-executable research. 项目地址: https://gitcode.com/gh_mirrors/pr/PRAXIST 点击查看 免费下载 本文以 PRAXIST 开源仓库中…

2026/10/13 1:42:12 阅读更多 →
Python NBA球员数据可视化分析:从数据清洗到图表绘制全攻略

Python NBA球员数据可视化分析:从数据清洗到图表绘制全攻略

简介:基于Python的NBA球员数据可视化分析项目,适合毕业设计、期末大作业及课程设计场景,面向需要完整数据挖掘与可视化示范的学生。项目代码逐行注释,梳理了从球员数据爬取、清洗到可视化展示的完整流程,包含K-Means聚…

2026/10/13 1:42:12 阅读更多 →
Leggedgym—config配置指南

Leggedgym—config配置指南

config配置指南 LeggedRobot基本配置文件 文件概述 `LeggedRobotCfg` 类 `LeggedRobotCfgPPO` 类 总结 go2基本配置文件 文件结构概述 `Go2RoughCfg` 类 `env` 子类 `terrain` 子类 `init_state` 子类 `commands` 子类 `control` 子类 `asset` 子类 `domain_rand` 子类 `reward…

2026/10/13 1:42:12 阅读更多 →

最新新闻

从决策记录到自动化流水线:architecture-decision-record 仓库“持续集成”ADR 示例的完整解读与落地实践

从决策记录到自动化流水线:architecture-decision-record 仓库“持续集成”ADR 示例的完整解读与落地实践

【免费下载链接】architecture-decision-record Architecture decision record (ADR) examples for software planning, IT leadership, and template documentation 项目地址: https://gitcode.com/gh_mirrors/ar/architecture-decision-record 点击查看 免费下载 …

2026/10/13 2:21:28 阅读更多 →
基于SpringBoot+Vue的前后端分离青年公寓服务平台设计与部署全解析

基于SpringBoot+Vue的前后端分离青年公寓服务平台设计与部署全解析

前后端分离的青年公寓服务平台,这类项目在最近几年的毕业设计和个人项目里出现频率相当高。用SpringBoot扛后端、Vue写前端界面、MyBatis管数据持久层、MySQL存业务数据,这套组合基本就是当前主流的全栈技术栈标配。我接触过不少类似的项目源码&#xff…

2026/10/13 2:21:28 阅读更多 →
超市收银系统源码解析:WinForm进销存设计与库存事务实战

超市收银系统源码解析:WinForm进销存设计与库存事务实战

简介:面向小型超市收银场景的毕业设计源码资源,适合计算机专业学生作为课程设计或毕业设计参考,也可供小型商户技术人员了解收银系统业务流程。系统围绕添加商品、商品销售、商品查询、计算器小工具四个核心模块展开,同时涉及库存…

2026/10/13 2:21:28 阅读更多 →
SpringBoot个人博客系统从零到一:选型、设计、实现与部署

SpringBoot个人博客系统从零到一:选型、设计、实现与部署

做了这么多年开发,接到最多的需求就是“帮我做个个人博客”,一到毕业季更多,十个学生里恨不得五个都是博客系统。刚开始我不太理解,为什么大家都扎堆做这个,后来带过几个毕设项目才明白,博客系统这个题目&a…

2026/10/13 2:21:28 阅读更多 →
RISC-V IDE MRS使用笔记(十四):用户反馈功能

RISC-V IDE MRS使用笔记(十四):用户反馈功能

RISC-V IDE MRS使用笔记(十四):用户反馈功能 今天给大家带来MRS用户反馈功能的分享,开发者们可以通过该功能向MRS技术支持提交:MRS相关操作咨询、改进建议或嵌入式开发中遇到的问题,用户也可以将上述内容直…

2026/10/13 2:21:28 阅读更多 →
Redis核心原理与生产实践:从数据结构到高可用架构详解

Redis核心原理与生产实践:从数据结构到高可用架构详解

1. 项目概述:为什么要系统学习Redis,而不是零散看教程1.1 核心需求解析:从面试题到生产环境,Redis到底卡住了多少人先说个直白的现象。我见过不少同学,Redis命令背得滚瓜烂熟,SET、GET、HSET随口就来&#…

2026/10/13 2:20:28 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →