active-group/reacl

Toggle red div and :embed-app-state

Closed this issue · 2 comments

In most cases, :embed-app-state ... and (reaction this ...) behave the same. I argue that in cases where the behaviour differs, e.g. situations involving higher-order components, users never want the behaviour of :embed-app-state. You should therefore always use (reaction this ...).

The following Reacl component hierarchy exemplifies the problem with :embed-app-state. At (1) we first use a normal div as a container element for a counter component. We use :embed-app-state to carry over the counter value. Later, we decide that it’s time for some toggleable redness, so we write a higher-order component daniel-red-div, which we use as a container in lieu of the simple div. The counter is now broken, because the counter value is embedded into the app-state of daniel-red-div, which has no use for it. :embed-app-state breaks abstractions.

Are there any situations where :embed-app-state is preferred over explicit reactions?

;; Just wrap children in a red div
(reacl/defclass daniel-red-div
  this
  [& children]

  local-state [red? false]

  handle-message
  (fn [_]
    (reacl/return :local-state (not red?)))

  render
  (dom/div
   (when red?
     {:style {:background-color "red"}})
   (dom/button
    {:onclick (fn [_] (reacl/send-message! this nil))}
    "toggle redness")
   children))

;; Increment a counter on button click
(reacl/defclass counting-button
  this
  counter
  []

  handle-message
  (fn [_]
    (reacl/return :app-state (inc counter)))

  render
  (dom/button
   {:onclick (fn [_] (reacl/send-message! this :inc))}
   "Inc"))

(reacl/defclass countainer
  this
  counter
  []

  render
  (dom/div ;; (1) try daniel-red-div to break the flow of app-state
   "Counter: " counter
   (counting-button
    (reacl/opt :embed-app-state
               (fn [_ childs]
                 childs))
    counter)))

(defn get-app-element []
  (gdom/getElement "app"))

(reacl/render-component
 (get-app-element)
 countainer
 0)

There is (opt :parent this) now, which results in the desired behaviour.
So I think we can close this Markus?