使用defonce定义含re-frame订阅的Atom需两次解引用的问题
问题解决:defonce存储re-frame订阅需两次解引用的问题
问题根源
你不需要把re-frame/subscribe返回的订阅信号再包裹一层reagent/atom——订阅信号本身就是一个可响应式的引用(实现了IRef接口),直接解引用(@)就能获取值,且Reagent会自动追踪其变化。
- 使用
def时,每次代码重载都会重新执行(reagent/atom (subscribe ...)),生成的新atom内装着新的订阅信号。在Reagent组件的反应式上下文中,@my-state解引用atom得到订阅信号后,Reagent会自动再解引用一次订阅信号获取值,所以看起来只需要一次@。 - 使用
defonce时,atom只会在首次加载时创建,后续重载不会更新。此时atom内的旧订阅信号无法被Reagent自动二次解引用,因此必须手动执行两次解引用(@@my-state)才能拿到最终值。
正确解决方案
直接用defonce存储订阅信号即可,不需要额外的reagent/atom:
(defonce my-state (re-frame/subscribe [::subs/photos]))
之后在组件中直接通过@my-state就能获取订阅的最新值,同时defonce会在代码重载时保留这个订阅引用(re-frame会自动处理订阅的重载更新)。
特殊场景:需手动维护atom值
如果确实需要用reagent/atom存储订阅的值(比如要手动修改值而非完全依赖订阅),可以用reagent/track!来同步订阅值到atom:
(defonce my-state (reagent/atom nil)) ;; 自动同步订阅值到atom,反应式更新 (reagent/track! #(reset! my-state @(re-frame/subscribe [::subs/photos])))
此时@my-state就能直接获取订阅的最新值,且defonce确保atom在重载时不被重置。
内容的提问来源于stack exchange,提问作者triplej
相关产品推荐
相关产品推荐

