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

欢迎!请参阅关于页面以获取更多关于它的工作方式的信息。

+1
ClojureScript
重新标签化

在热重载中是否有一种方法可以仅重绘应用程序 affected 部分?

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 呢?
即使将相同的即时重新加载方法应用于纯JS,React本身也不会对此有任何不同处理。

导致事物被"替换"的原因是,当你通过热重载重新定义一个函数时,`(identical? old new)`返回false。所以在你的例子中,`app`和`form`具有"新"的定义,因此React将它们替换。如果您只是从REPL调用`(mount!)`,则`input`状态不会被修改并且"存活",因为在实际的比较中并没有替换实际的DOM节点。
哦,不知道比较也是在函数本身上进行的,这解释了很多,谢谢!
...