2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请参阅 关于 页以了解更多有关此内容的工作方式的信息。

+1
ClojureScript
重标记

有办法在热重载时只重新渲染受影响的应用程序部分吗?

Figwheel 文档只提到重新挂载整个应用程序(在这种情况下,将丢失组件的所有本地状态):https://figwheel.org/docs/hot_reloading.html#re-rendering-ui-after-saving-a-file

在 shadow-cljs 文档中还没有找到关于这一点的内容。迄今为止,我所见过的所有应用程序要么在热重载时根本不重新渲染,要么进行重新挂载。

那么,比较热重载前后 VDOM 的障碍有哪些?根据这个差异来更新 DOM?或者这已经实现了?

虽然 Figwheel/shadow-cljs 与 React/VDOM 独立,但他们没有实现这种行为是可以预料的,但也许有一些库或良好的方法来实现这一点?

2 个答案

+2

实际上这并不是“重新挂载”,而只是一个更新,这并不意味着整个应用程序的 DOM 都在替换。调用顶级 render 并不与更新一个组件不同,React 仍然像往常一样执行 diff 和 patch。


编辑了
嗯,可能我应该上传一些示例仓库,但`reagent/render-component`确实为我重新渲染了整个应用。或许您手头有参考项目,这样我就可以对比一下,找出我出错在哪里了?
已上传最小化重复示例: https://github.com/fjolne/reagent-hot-reload

如果用户在输入框中输入了一些文本,然后更改了标题文本,则热重载重新渲染将清除输入内容。

编辑了
在这种情况下这是预期的,因为输入的值没有在任何地方存储,除了DOM之外,所以从React的角度来看,输入框中没有值。

更正:在Reagent中也仍然如此,但在plain React中并非如此。我认为这与Reagent对局部状态的独特理解有关。
但为什么如果它不在 diff 中,输入字段也会更新?使用 Reagent 原子来持有数据而不是 DOM 时也会有同样的行为。

编辑:已看到更正,感谢深入探讨 :)
+2
by

通常,像 fulcrore-frame 这样的框架对状态及如何管理状态有明确的规则。使用它们。

在工具层面上这样做会非常困难,这就是为什么 figwheel 和 shadow-cljs 都只负责重新加载代码,而将状态管理留给实际应用。我甚至不确定在没有完全限制可以在代码中做什么的情况下,在工具层面上能否做到这一点。

by
我大量使用 re-frame,但有些情况下(简单表单、下拉菜单展开状态等)使用本地状态似乎比生成 re-frame 事件处理器/订阅更简洁。
by
此外,正如上面提到的,React 本身确实可以处理这个问题。那么为什么不可能直接在重新加载前后状态之间生成一个普通的 VDOM diff 呢?
by
如果你对纯 JS 应用套用相同的热重载方法,React 本身也不会对此有特别的处理。

导致实体被“替换”的原因是,在通过热重载重新定义函数时,`(identical? old new)` 返回 false。所以,在你的示例中,`app` 和 `form` 有“新”的定义,React 就将它们替换了。如果你仅仅在交互式环境中调用 `(mount!)`,则 `input` 状态不会受到影响并“存活下来”,因为实际的比较并没有替换实际的 DOM 节点。
哦,没想到比较还会对函数本身进行,这解释了很多问题,谢谢!
...