如何为试剂组件编写装饰器

时间:2017-06-13 10:55:12

标签: clojure decorator clojurescript reagent re-frame

我有一些类似的试剂成分,可以某种方式呈现给定的数字:

(defn plain-number [n]
  [:h1 n])

(defn pie-chart [n]
  (render-fancy-chart n))

还有一些(简化)状态:

(def state (r/atom {:a 5 :b 10 :c 7}))

我知道如何编写一个组件,可以访问该状态并使用其中一个组件来呈现状态:

(def fetch-and-render-pie [k]
   (let [v (get @state k)]
     [pie-chart v]))

[fetch-and-render-pie :a] ; renders pie with 5

到目前为止,这么好。但那是耦合和重复的。

目标:

装饰器会很好,可以获取某些状态并将其传递给子级。用法看起来像这样:

[fetch :a
  [pie-chart]]

可能的解决方案:

(defn fetch [k wrapped]
  (let [v (get @state k)]
    (conj wrapped v)))

这很有用,但它与组件定义的向量混淆,它假定了很多包装的组件的参数。它对链式装饰器失败了。

必须有一个聪明而强大的解决方案。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

你不能仅仅因为你将一个参数传递给它而摆脱对装饰组件参数的假设,并且应该知道如何以与函数调用相同的方式来完成它。但是你不需要将vector传递给你的装饰器,只需要一个组件本身就可以工作:

(defn fetch [k component]
  (let [v (get @state k)]
    [component v]))

[fetch :test pie-chart] ; ~ [pie-chart (get @state :test)]

对于链接,您需要支持component的额外参数:

(defn fetch [k component & args]
  (let [v (get @state k)]
    (into [component v] args)))

(defn prepare [s component & args]
  (let [v (keyword s)]
    (into [component v] args)))

[prepare "test" fetch pie-chart {:colourful true}]
; ~ [pie-chart (get @state (keyword "test")) {:colourful true}]

这类似于HOF和线程宏。

答案 1 :(得分:0)

仅使用试剂,我们可以使用光标

(defn com-a [state]
  (fn []
    [:h1 @state]))

(defn fetch [db]
  (let [state (reagent/cursor db :k)] ; assume {:k "dd"}
    (fn []
      [com-a state])))

重新加框架

(re-frame/reg-sub
  :chart-data
  (fn [db [_ query]]
    (get-in db query)))

(defn com-a [state]
  (fn []
    [:h1 @state]))

(defn fetch [db]
  (let [state (re-frame/subscribe [:chart-data [:k]])]
    (fn []
      [com-a state])))