Reagent 101 / why Form 2 components need to return a function

icncsx

icncsx

Posted on July 8, 2020

Reagent 101 / why Form 2 components need to return a function

Let's take a look at a canonical example of a Form 2 component.

(defn app-view []
  (let [counter (r/atom 0)] ;; setup
    (fn [] ;; render fn
      [:div
       [:p @counter]
       [:button
        {:on-click
         (fn [e]
           (swap! counter inc))}
        "Increment!"]])))
Enter fullscreen mode Exit fullscreen mode

We initialize some local state and return a function that returns some Hiccup. On click, we would see the correct behavior: the counter incrementing.

Imagine if we didn't return that inner function. What would happen?

(defn app-view [] ;; render fn
  (let [counter (r/atom 0)] ;; setup
    [:div
     [:p @counter]
     [:button
      {:on-click
       (fn [e]
         (swap! counter inc))}
      "Increment!"]]))
Enter fullscreen mode Exit fullscreen mode

The counter feature would break. Remember: in a Form 2 component, we have an outer function that is run only once and an inner function that is run every time the component re-renders.

When we don't have an inner function, the outer function assumes the role of a render function.

In the example above, this means that app-view gets re-run every time the component renders. Do you understand the problem now? The component-state is getting re-created with every render. We get a new counter r/atom on each re-render.

If a component does not re-render, it may be because you're re-creating state on every re-render.

Warmly,
DH

💖 💪 🙅 🚩
icncsx
icncsx

Posted on July 8, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related