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 中仍然会发生这种情况,但在纯 React 中不会发生。我猜这与 Reagent 对局部状态自己的概念有关。
但是,如果输入字段不在diff中,为什么还要更新它?使用Reagent原子来保存数据而不是DOM时,也会有同样的行为。

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

一般来说,像fulcrore-frame这样的框架对状态及其管理有一套明确的规则。请使用这些。

在工具级别进行这种操作会非常困难,这也是为什么figwheel和shadow-cljs都只处理代码的重新加载,而将状态的管理留给实际应用的原因。我甚至不确定在没有完全限制你可以在代码中执行的操作的情况下,是否可以在工具级别完成这项工作。

by
虽然我主要依赖于re-frame,但在某些情况下(简单的表单、下拉菜单展开状态等)使用本地状态似乎比生成re-frame事件处理程序/订阅更简洁。
by
正如上面提到的,React本身也处理了这个问题。那么为什么不可能在重新加载前后状态之间简单地比较一个常规的VDOM diff呢?
by
如果你将相同的即时重载方法应用于纯JavaScript,React本身对这点处理并无差异。

导致事物“替换”的原因是,当你通过热重载重新定义一个函数时,`(identical? old new)` 返回 false。所以,在你的示例中,`app` 和 `form` 有“新”的定义,因此 React 会替换它们。如果你只是从 REPL 中调用 `(mount!)`,则 `input` 状态不会受到影响,并且“存活”下来,因为实际的差分并不替换实际的 DOM 节点。
哦,不知道比较也适用于函数本身,这解释了很多,谢谢!”
...