嵌套Reagent组件更新不生效?编辑子组件需改父组件才刷新
问题场景
用Reagent搭建三层嵌套组件(APP嵌套DASHBOARD,DASHBOARD嵌套NAV)时,出现热更新异常:修改最底层的NAV组件并保存后,浏览器不会同步显示更改;只有修改中间层的DASHBOARD组件并保存,NAV的修改才会跟着生效。调整组件的目录结构后,问题依旧存在。
相关代码示例:
app/core.cljs
(ns app.core (:require [app.views.dashboard :as dash])) (defn app[] [dash/dashboard])
app/views/dashboard.cljs
(ns app.views.dashboard (:require [app.components.nav :as nav])) (defn dashboard[] [:div [:div "Dashboard"] [nav/nav]])
app/components/nav.cljs
(ns app.components.nav) (defn nav[] [:div "Navigation"])
shadow-cljs.edn配置片段:
{:app {:target :browser :modules {:main {:entries [app.core]}}} ... }
问题原因
ShadowCLJS默认只重新加载你修改的文件对应的命名空间,但Reagent组件渲染依赖组件函数的引用。修改NAV组件后,ShadowCLJS更新了NAV的命名空间,但上层的DASHBOARD组件没有收到重新渲染的通知,仍在调用旧的NAV函数;只有当DASHBOARD自身被重新加载时,才会获取到NAV的最新函数引用并渲染。
解决办法
办法1:给子组件添加热更新钩子,强制全局刷新
在NAV组件的文件中添加热更新完成后的钩子函数,调用Reagent的全局刷新方法,让所有组件重新渲染,确保用上最新的NAV组件。
修改后的nav.cljs:
(ns app.components.nav (:require [reagent.core :as r])) (defn nav[] [:div "Navigation"]) ;; 热更新完成后强制所有组件刷新 (defn ^:dev/after-load reload [] (r/force-update-all))
办法2:调整ShadowCLJS的热更新策略
在shadow-cljs.edn的app配置中,给:devtools添加:reload-strategy :full,让ShadowCLJS热更新时重新加载所有相关命名空间,保证上层组件能获取到子组件的最新引用:
{:app {:target :browser :modules {:main {:entries [app.core]}} :devtools {:reload-strategy :full}} ... }
注意:此方案会增加热更新的耗时,适合组件数量较少的项目。
办法3:升级ShadowCLJS到最新版本
部分旧版本的ShadowCLJS存在间接引用组件热更新的bug,升级到最新稳定版可直接解决这类问题。执行以下命令:
npm update shadow-cljs --save-dev
验证方式
修改NAV组件内容并保存后,观察浏览器是否自动刷新并显示最新内容;若仍有问题,查看ShadowCLJS的终端输出,确认是否存在报错或加载异常信息。
内容的提问来源于stack exchange,提问作者Somé

