clojure - 为什么多方法不能用作试剂/重组的功能?

标签 clojure clojurescript reagent re-frame

在一个使用Reagent和Re-frame的小型应用程序中,我正在使用多种方法来调度应基于应用程序状态中的值显示哪个页面:

(defmulti pages :name)

(defn main-panel []
  (let [current-route (re-frame/subscribe [:current-route])]
    (fn []
      ;...
      (pages @current-route))))

然后我有一些方法,例如:
(defmethod layout/pages :register [_] [register-page])
register-page函数将生成实际 View 的位置:
(defn register-page []
  (let [registration-form (re-frame/subscribe [:registration-form])]
    (fn []
      [:div
       [:h1 "Register"]
       ;...
       ])))

我尝试了changing my app so that the methods generated the pages directly,如:
(defmethod layout/pages :register [_]
  (let [registration-form (re-frame/subscribe [:registration-form])]
    (fn []
      [:div
       [:h1 "Register"]
       ;...
       ])))

导致没有页面呈现。在我的主面板中,我changed the call to pages to square brackets,以便Reagent可以看到它:
(defn main-panel []
  (let [current-route (re-frame/subscribe [:current-route])]
    (fn []
      ;...
      [pages @current-route])))

并导致第一个访问的页面起作用,但是此后,单击链接(这会导致当前路线更改)无效。

在首先加载的文件(包含init函数)中,所有定义单个方法的 namespace 都是必需的,而且我可以选择任何一个页面并显示它的事实证明代码正在加载(然后,切换到另一页不会不起作用):

https://github.com/carouselapps/ninjatools/blob/master/src/cljs/ninjatools/core.cljs#L8-L12

为了调试正在发生的事情,我定义了两条路由,:about:about2,一条作为函数,一条作为方法:
(defn about-page []
  (fn []
    [:div "This is the About Page."]))

(defmethod layout/pages :about [_]
  [about-page])

(defmethod layout/pages :about2 [_]
  (fn []
    [:div "This is the About 2 Page."]))

并使布局打印出调用pages的结果(当然必须使用显式调用而不是方括号)。包装的函数(起作用的函数)返回:
[#object[ninjatools$pages$about_page "function ninjatools$pages$about_page(){
return (function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Keyword(null,"div","div",1057191632),"This is the About Page."], null);
});
}"]]

当方法返回时:
#object[Function "function (){
return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Keyword(null,"div","div",1057191632),"This is the About 2 Page."], null);
}"]

如果我将方法更改为:
(defmethod layout/pages :about2 [_]
  [(fn []
     [:div "This is the About 2 Page."])])

也就是说,以 vector 返回函数,然后它开始工作。而且,如果我对包装函数进行了反向更改,则它以与方法相同的方式开始失败:
(defn about-page []
  (fn []
    [:div "This is the About Page."]))

(defmethod layout/pages :about [_]
  about-page)

由于Reagent的语法是[function],所以有点意义,但是应该自动调用该函数。

我还开始将@current-route输出到浏览器,如下所示:
[:main.container
 [alerts/view]
 [pages @current-route]
 [:div (pr-str @current-route)]]

并且我验证了@current-route是否已正确修改并且输出已更新,但不是[pages @current-route]

我的应用程序的完整源代码可以在这里找到:https://github.com/carouselapps/ninjatools/tree/multi-methods

Update: corrected the arity of the methods following Michał Marczyk's answer.

最佳答案

因此,像这样的组件:[pages @some-ratom]将在pages更改或@some-ratom更改时重新呈现。

从试剂的 Angular 来看,pages自上次以来就没有改变过,它仍然是以前的相同多方法。但是@some-ratom可能会更改,因此可能触发重新提交。

但是发生在此重新渲染时,将使用pages的缓存版本来完成。毕竟,对于pages而言,似乎没有改变。它仍然是以前的相同方法。

当然,pages的缓存版本将是呈现的pages的第一个版本-mutlimethod和的第一个版本,而不是,我们希望看到使用的新版本。

试剂执行此缓存,因为它必须处理Form-2函数。它必须保留返回的render函数。

最重要的是:由于存在缓存,除非您找到一种方法来完全炸毁该组件并重新开始,否则多重方法将无法很好地工作,这是目前最受好评的方法:
^{:key @current-route} [pages @current-route]当然,炸毁该组件并重新启动可能会有其自身的不受欢迎的含义(取决于该组件中保留的本地状态)。

模糊相关的背景:
https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components#appendix-a---lifting-the-lid-slightly
https://github.com/Day8/re-frame/wiki/When-do-components-update%3F

关于clojure - 为什么多方法不能用作试剂/重组的功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33299746/

相关文章:

string - Clojure 中惯用的字符串旋转

clojure - 将 zip 文件写入 Clojure 中的文件

Clojure 调用一系列函数并存储它们的返回值

clojure - 什么时候使用 Clojure 的闭包?

clojure - 在 ClojureScript 命名空间中引用宏

clojurescript - 将庞大的 JavaScript 代码转换为优雅的 Clojurescript 代码

Clojure 合并函数

clojure - 如何防止 Clojure Reagent 中的 HTML 转义(类似 Hiccup)

html - 在 Reagent 中使用 colspan 渲染表格元素

clojure - 如何在 HTML 中漂亮地打印 Clojure 数据结构?