10

我正在编写一个 Clojurescript 应用程序,使用 Reagent 使我的组件具有反应性。

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

  1. 通过我的组件传递我的原子作为输入,或者
  2. 将原子用作全局变量并让它们“影响”我的组件?

在本教程中,他们使用后一种选项,但是为了保持我的功能纯净,我选择了前一种。

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

4

2 回答 2

10

如果你让你的组件接受原子作为参数,那么你可以让它们更易于重用和测试。

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

;; 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])])

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

 app-db  >  subscriptions
   ^             
handlers        v
   ^             
 events  <  components
  1. 不仅仅是编写组件并将它们直接连接app-db到全局subscriptions原子(app-dbapp-db

  2. app-db然后,组件创建events的只是描述组件意图的一小段数据,而不是直接搞乱组件。

  3. 这些事件被发送到handlers,这些函数将event和 currentapp-db作为参数并返回一个新的app-db. 然后app-db替换现有的,触发订阅者将数据向下传递给组件等等。

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

于 2016-07-11T17:40:05.100 回答
10

我更喜欢向组件传递一个随机数。Re-frame 越来越流行https://github.com/Day8/re-frame

传入一个 Ratom 不会使你的函数更加纯粹,原子仍然可以产生副作用。它确实使您的组件更加灵活和可重用,因为它们定义了它们的依赖关系。

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

(defn my-component []
  (let [x (reaction (:x @db)]
    (fn []
      [:div @x]))

该组件只会在 :x 更改时重新渲染(而不是在 db 中发生任何更改时。创建反应可能变得乏味,这是 re-frame 的吸引力之一。

(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])

反应是表达数据流的一种非常简洁的方式。在这里,您从一个包含 x 和 y 值的随机数开始。然后你建立一个只观察 x 值的反应 b。接下来,引入另一个观察 b 和 10 之和的反应 c。然后创建一个反应性渲染 c 的组件。请注意,当您单击“inc x”按钮时,视图会更新为应用表达式的结果。当您单击“inc y”按钮时,什么也没有发生。检查控制台以确认仅在单击“inc x”时才打印“Rendering view-c”消息。这是一件非常好的事情,因为视图不以任何方式依赖于 y。如果您要在视图中取消引用 a 而不是 c,即使 y 更改,它也会重新渲染。Reagent 通过 requestAnimationFrame 对反应和随机数做出反应。所以,

于 2016-07-11T17:40:56.877 回答