请在 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 atom来存储数据而不是DOM时,也会出现相同的行为。

更新:看到了更正,感谢深入挖掘 :)
+2 投票

总的来说,像fulcrore-frame这样的框架对状态以及如何管理状态有明确定义的规定。可以使用它们。

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

我很依赖re-frame,但在某些情况下(简单的表单、下拉列表展开状态等)使用局部状态而不是产生re-frame事件处理器/订阅似乎更简洁。
此外,如上所述,React本身确实可以处理这一点。那么为什么就不能直接使用预加载数据和重新加载数据之间的常规VDOM diff呢?
React 本身在你对纯 JS 应用相同的热重载方法时,并没有做出任何不同的处理。

导致东西被“替换”的原因是,当你通过热重载重新定义一个函数时,`(identical? old new)` 返回 false。因此,在你的例子中,“app”和“form”有“新”的定义,所以 React 替换了它们。如果你只是从 REPL 中调用 `(mount!)`,`input` 状态不会受到影响,并且“ survive”了,因为实际的 diff 并没有替换实际的 DOM 节点。
哦,不知道比较还会针对函数本身进行,这个解释了很多,谢谢!
...