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对局部状态的自身理解有关。
但为什么输入字段在没有差异的情况下也会被更新呢?使用Reagent原子来保存数据而不是DOM时也会有同样的行为。

编辑:看到更正了,感谢加入讨论 :)
+2

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

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

我非常依赖re-frame,但有时(简单的表单、下拉菜单展开状态等)使用本地状态似乎比产生re-frame事件处理器/订阅更简洁。
此外,如前所述,React本身也处理这一点。那么为什么不可能仅仅在重新加载前后的状态之间进行常规的VDOM差异比较呢?
如果你将相同的即时重载方法应用于纯JavaScript,React自身并不会以任何不同方式处理。

导致事情被“替换”的原因是,当你通过即时重载重新定义一个函数时,`(identical? old new)`返回false。所以,在你的例子中,`app`和`form`有“新”的定义,因此React将它们替换。如果你只是从REPL调用`(mount!)`,那么`input`状态不会被触及,并且“生存”下来,因为实际的diff没有替换实际的DOM节点。
哦,不知道比较也涉及到函数本身,这解释了很多,谢谢!
...