问题描述
在我正在构建的使用Reagent和Re-frame的小型应用程序中,我正在使用多种方法来调度应基于应用程序状态中的值显示哪个页面:
In a small app I'm building that uses Reagent and Re-frame I'm using multi-methods to dispatch which page should be shown based on a value in the app state:
(defmulti pages :name)
(defn main-panel []
(let [current-route (re-frame/subscribe [:current-route])]
(fn []
;...
(pages @current-route))))
然后我有一些方法,例如:
and then I have methods such as:
(defmethod layout/pages :register [_] [register-page])
register-page
函数将生成实际视图的位置:
where the register-page
function would generate the actual view:
(defn register-page []
(let [registration-form (re-frame/subscribe [:registration-form])]
(fn []
[:div
[:h1 "Register"]
;...
])))
我尝试更改我的应用程序,以便方法可以直接生成页面的方法,例如:
I tried changing my app so that the methods generated the pages directly, as in:
(defmethod layout/pages :register [_]
(let [registration-form (re-frame/subscribe [:registration-form])]
(fn []
[:div
[:h1 "Register"]
;...
])))
,导致没有页面可以渲染.在主面板中,我将对 pages
的调用更改为方括号,以便Reagent对此具有可见性:
and that caused no page to ever be rendered. In my main panel I changed the call to pages
to square brackets so that Reagent would have visibility into it:
(defn main-panel []
(let [current-route (re-frame/subscribe [:current-route])]
(fn []
;...
[pages @current-route])))
导致第一个访问的页面正常工作,但是此后,单击链接(这会导致当前路线更改)无效.
and that caused the first visited page to work, but after that, clicking on links (which causes current-route to change) has no effect.
在首先加载的文件(包含init函数)中,所有定义单个方法的名称空间都是必需的,而且我可以选择任何一个页面并显示它的事实证明代码正在加载(然后,切换到另一个页面不起作用):
All the namespaces defining the individual methods are required in the file that is loaded first, that contains the init function, and the fact that I can pick any single page and have it displayed proves the code is loading (then, switching to another page doesn't work):
https://github.com/carouselapps/ninjatools/blob/master/src/cljs/ninjatools/core.cljs#L8-L12
为了调试正在发生的事情,我定义了两条路由,:about
和:about2
,一条作为函数,一条作为方法:
In an effort to debug what's going on, I defined two routes, :about
and :about2
, one as a function and one as a method:
(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
的结果(当然必须使用显式调用而不是方括号).包装的函数(起作用的函数)返回:
and made the layout print the result of calling pages
(had to use the explicit call instead of the square brackets of course). The wrapped function, the one that works, returns:
[#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."])])
,即以向量返回函数,然后开始工作.而且,如果我对包装函数进行了反向更改,它会以与方法相同的方式开始失败:
that is, returning the function in a vector, then, it starts to work. And if I make the reverse change to the wrapped function, it starts to fail in the same manner as the method:
(defn about-page []
(fn []
[:div "This is the About Page."]))
(defmethod layout/pages :about [_]
about-page)
由于Reagent的语法为 [function]
,所以有点含义,但应该自动调用该函数.
Makes a bit of sense as Reagent's syntax is [function]
but it was supposed to call the function automatically.
我还开始将 @ current-route
输出到浏览器,如下所示:
I also started outputting @current-route
to the browser, as in:
[:main.container
[alerts/view]
[pages @current-route]
[:div (pr-str @current-route)]]
并且我验证了 @ current-route
是否已正确修改并更新了输出,只是没有 [pages @ current-route]
.
and I verified @current-route
is being modified correctly and the output updated, just not [pages @current-route]
.
可在以下位置找到我的应用程序的完整源代码: https://github.com/carouselapps/ninjatools/tree/multi-methods
The full source code for my app can be found here: https://github.com/carouselapps/ninjatools/tree/multi-methods
更新:根据MichałMarczyk的回答纠正了方法的局限性.
Update: corrected the arity of the methods following Michał Marczyk's answer.
推荐答案
我没有所有详细信息,但是显然,当我渲染这样的页面时:
I don't have all the details, but apparently, when I was rendering pages like this:
[:main.container
[alerts/view]
[pages @current-route]]
试剂未能注意到 pages
取决于 @ current-route
的值. Chrome React插件帮助我弄清楚了.我尝试使用替代而不是订阅的方式,这似乎很好用.幸运的是,告诉试剂/反应元素的键很容易:
Reagent was failing to notice that pages
depended on the value of @current-route
. The Chrome React plugin helped me figure it out. I tried using a ratom instead of a subscription and that seemed to work fine. Thankfully, telling Reagent/React the key to an element is easy enough:
[:main.container
[alerts/view]
^{:key @current-route} [pages @current-route]]
那很好.
这篇关于为什么多方法不能用作试剂/重组的功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!