Clojurescript,Reagent:将原子作为输入传递,还是用作全局变量?

Boy*_*nbi 7 clojurescript reactjs reagent

我正在编写一个Clojurescript应用程序,使用Reagent使我的组件被反应.

我有一个简单的问题.我是不是该

  1. 通过我的组件传递我的原子作为输入,或
  2. 使用原子作为全局变量,让它们"副作用"我的组件?

教程中,他们使用后一种选择,但是在尝试保持我的功能纯净时,我选择了前者.

我是否正确地说将它们用作全局变量(除了在定义组件输入时不那么冗长)还会阻止重新呈现未使用原子状态的整个父组件?

Tim*_*ley 9

我更喜欢将鼠标传递给组件.重新框架正在变得流行https://github.com/Day8/re-frame

通过一个输入不会使你的功能更纯净,原子仍然可以副作用.它确实使您的组件更加灵活和可重用,因为它们定义了它们的依赖关系.

无论是引用全局数据库还是传入数据库,它都不会直接影响重新呈现.渲染时间的信号图是根据矢量内部deref的出现构建的,它不关心ratom来自何处.但是,通过创建反应可以提高效率.

(defn my-component []
  (let [x (reaction (:x @db)]
    (fn []
      [:div @x]))
Run Code Online (Sandbox Code Playgroud)

这个组件只会在以下情况下重新渲染:x会发生变化(而不是db中的任何变化.创建反应会变得乏味,这是重新构建的吸引力之一.

(ns whip.view.reactions
  (:require [reagent.core :as reagent]
            [devcards.core :refer-macros [defcard-rg deftest]])
  (:require-macros [reagent.ratom :refer [reaction]]))
(def a (reagent/atom {:x 100 :y 200})) (def b (reaction (:x @a)))
(def c (reaction (+ @b 10)))
(defn view-c []
  (prn "Rendering view-c") [:div
  [:div @c]
  [:button {:on-click (fn [e] (swap! a update :x inc))} "inc x"]
  [:button {:on-click (fn [e] (swap! a update :y inc))} "inc y"]])
(defcard-rg reaction-example [view-c])
Run Code Online (Sandbox Code Playgroud)

反应是表达数据的一种非常简洁的方式.在这里,您将从包含x和y值的ratom开始.然后构建一个只观察x值的反应b.接下来,引入另一个观察b和10之和的反应c.然后创建一个反应性地呈现c的组件.请注意,单击"inc x"按钮时,视图将更新为应用表达式的结果.单击"inc y"按钮时,没有任何反应.检查控制台,确认只有在单击"inc x"时才会打印"Rendering view-c"消息.这是一件非常好的事情,因为视图不以任何方式依赖于y.如果你在视图中deref a而不是c,那么即使y改变了它也会被重新渲染.试剂通过requestAnimationFrame对反应和ratoms作出反应.因此,改变许多大鼠和依赖它们的反应只会导致一个渲染阶段.


Dan*_*nce 7

如果您使组件接受原子作为参数,那么您可以使它们更可重用且更容易测试.

如果您选择将整个应用程序状态保存在单个原子中,然后使用游标将其传递给子组件,则尤其如此.

;; setup a single instance of global state
(defonce app-state
  (reagent/atom {:foo 0 :bar 0})

;; define a generic counter component that knows
;; nothing about the global state
(defn counter
  [count]
  [:div
    [:button {:onclick #(swap! count inc) "+"]
    [:span @count]])

 ;; define counter components and give them access to
 ;; specific context within the global state
 (defn app
   [state]
   [counter (reagent/cursor app-state [:foo])]
   [counter (reagent/cursor app-state [:bar])])
Run Code Online (Sandbox Code Playgroud)

如果您决定将Reagent与Re-frame一起使用,您甚至可以更进一步.重新框架鼓励您使用看起来像这样的特定架构来构建您的应用程序.

 app-db  >  subscriptions
   ^             
handlers        v
   ^             
 events  <  components
Run Code Online (Sandbox Code Playgroud)
  1. app-db您可以编写subscriptions哪些只是从中选择/查询某些数据的函数,app-db并在每次app-db更改时将其传递给组件,而不仅仅是编写组件并将它们直接连接到全局atom().

  2. 然后,app-db组件创建events哪些只是描述组件意图的小块数据,而不是直接与组件混乱.

  3. 这些事件被发送到handlers,这些函数接受event和当前app-db作为参数并返回一个新的app-db.然后app-db替换现有的,触发订户将数据传递给组件,依此类推.

如果你发现你的Reagent项目有点纠结并且Re-frame自述文件是一个很好的读取,无论你是否决定使用它,这绝对是有帮助的.