Skip to content
Andre R edited this page May 26, 2016 · 12 revisions

Avoiding ambiguity of attributes / children

You can explicitly set the attributes to {} and avoid the ambiguity of children vs attributes that would need to be resolved during runtime. Observe:

(macroexpand-1 '(html [:a (foo)]))
=>
(clojure.core/let
 [attrs99902 (foo)]
 (clojure.core/apply
  js/React.createElement
  "a"
  (if (clojure.core/map? attrs99902) 
        (sablono.interpreter/attributes attrs99902) 
        nil)
  (if (clojure.core/map? attrs99902) 
        nil 
        [(sablono.interpreter/interpret attrs99902)])))


(macroexpand-1 '(html [:a {} (foo)]))
=> (js/React.createElement "a" nil (sablono.interpreter/interpret (foo)))

Avoid for

Not really sablono specific but I think it fits here: for macro generates a ton of code because it is very powerful. Often, though, you don't need the lazyness of for and the flexibility and would be better off with a simple mapv.

(macroexpand-1 '(for [x y]
                  [:span "hi"]))
; => <omitted since it's very very long>

Avoid interpretation call

You can further add a type hint to avoid the call to interpret:

(macroexpand-1 '(html [:a {} ^String (foo)]))
=> (js/React.createElement "a" nil (foo))

Obviously, only do this if your (foo) function call returns React elements.

Note that, even though the type hint says ^String, the function (or variable) doesn't have to return a string. This is only used because this type hint is the only one that sablono recognizes and removes the interpretation call. The function can also return a vector or list of (React) elements.

(Hack) Manually minify calls to React.creatElement

Use at your own risk.

Since calls to React.createElement don't get minified by the google closure compiler, you can manually create an alias and rewrite the code generated by sablono: In your clj macros file:

(defmacro html
  "Rewrites (js/React.createElement ...)
   to (js/R ...)
   needs proper externs."
  [body]
  (let [sab (sablono.compiler/compile-html body)]
    (clojure.walk/postwalk-replace {'js/React.createElement 'js/R} sab)))

You should also add an externs file containing:

var R = function(type, props, children) {};

and further create the alias somewhere before you render anything:

(set! js/R js/React.createElement)

and then your code will look like this:

(macroexpand-1 '(html [:a "hi"]))
=> (js/R "a" nil "hi")
Clone this wiki locally