All arguments allowed

2014-02-15

If it looks like a function…

Calling a component in Reagent looks a lot like a function call. Now it also works like one.

Before 0.4.0, component functions were always called with three arguments: a map of attributes, a vector of ”children”, and the current React component.

This was confusing, and an unnecessary limitation, so now component functions get exactly the same arguments you pass to them.

In other words, you can now do this:

hide

Example

Hello, world!

Source

(defn hello-component [name]
  [:p "Hello, " name "!"])

(defn say-hello []
  [hello-component "world"])

In the above example, it wouldn’t make any difference at all if hello-component had been called as a function, i.e with parentheses instead of brackets (except for performance, since components are cached between renders if the arguments to them don’t change).

But there is one drawback: component function no longer receives the ”current component” as a parameter. Instead you’ll have to use reagent.core/current-component in order to get that. Beware that current-component is only valid in component functions, and must be called outside of e.g event handlers and for expressions, so it’s safest to always put the call at the top, as in my-div here:

hide

Example

Some text.

Some other text in bold.

Source

(ns example
  (:require [reagent.core :as r]))
(defn my-div []
  (let [this (r/current-component)]
    (into [:div.custom (r/props this)]
          (r/children this))))

(defn call-my-div []
  [:div
   [my-div "Some text."]
   [my-div {:style {:font-weight 'bold}}
    [:p "Some other text in bold."]]])

Note: r/props and r/children correspond to React’s this.props and this.props.children, respectively. They may be convenient to use when wrapping native React components, since they follow the same conventions when interpreting the arguments given.

Other news in 0.4.0

  • React has been updated to version 0.9.0.
  • You can now use any object that satisfies ifn? as a component function, and not just plain functions. That includes functions defined with deftype, defrecord, etc, as well as collections like maps.
  • reagent.core/set-state and reagent.core/replace-state are now implemented using an reagent.core/atom, and are consequently async.
  • Keys associated with items in a seq (e.g ”dynamic children” in React parlance) can now be specified with meta-data, as well as with a :key item in the first parameter as before. In other words, these two forms are now equivalent: ^{:key foo} [:li bar] and [:li {:key foo} bar].
  • Performance has been improved even further. For example, there is now practically no overhead for tracking derefs in components that don’t use atoms. Allocations and memory use have also been reduced.
  • Intro and examples have been tweaked a little to take advantage of the new calling conventions.

New svg example

There is also a new, elegant and simple example of using svg with Reagent, written by Jonas Enlund. It also shows how you can use Reagent’s new calling convensions, and looks like this:

hide

Example

The points are draggable and the slider controls history
Fork me on GitHub