我正在编写一个 Clojurescript 应用程序,使用 Reagent 使我的组件具有反应性。
我有一个简单的问题。我是不是该
- 通过我的组件传递我的原子作为输入,或者
- 将原子用作全局变量并让它们“影响”我的组件?
在本教程中,他们使用后一种选项,但是为了保持我的功能纯净,我选择了前一种。
我是否正确地说将它们用作全局变量(除了在定义组件输入时不那么冗长)可以防止重新渲染未使用原子状态的整个父组件?
我正在编写一个 Clojurescript 应用程序,使用 Reagent 使我的组件具有反应性。
我有一个简单的问题。我是不是该
在本教程中,他们使用后一种选项,但是为了保持我的功能纯净,我选择了前一种。
我是否正确地说将它们用作全局变量(除了在定义组件输入时不那么冗长)可以防止重新渲染未使用原子状态的整个父组件?
如果你让你的组件接受原子作为参数,那么你可以让它们更易于重用和测试。
如果您选择将整个应用程序状态保存在单个原子中,然后使用游标将其传递给子组件,则尤其如此。
;; 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
不仅仅是编写组件并将它们直接连接app-db
到全局subscriptions
原子(app-db
app-db
app-db
然后,组件创建events
的只是描述组件意图的一小段数据,而不是直接搞乱组件。
这些事件被发送到handlers
,这些函数将event
和 currentapp-db
作为参数并返回一个新的app-db
. 然后app-db
替换现有的,触发订阅者将数据向下传递给组件等等。
如果您发现您的 Reagent 项目有点纠结,并且Re-frame 自述文件是一本很好的读物,无论您决定是否使用它,这绝对会有所帮助。
我更喜欢向组件传递一个随机数。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 对反应和随机数做出反应。所以,