2013-12-19 12:11:02 +00:00
2014-01-17 10:12:11 +00:00
# Reagent
2013-12-19 12:11:02 +00:00
2014-01-10 13:51:27 +00:00
A simple [ClojureScript ](http://github.com/clojure/clojurescript ) interface to
[React ](http://facebook.github.io/react/ ).
2013-12-19 12:11:02 +00:00
2014-01-17 10:12:11 +00:00
[Reagent ](http://holmsand.github.io/reagent/ ) provides a way to write efficient
2014-01-10 13:51:27 +00:00
React components using (almost) nothing but plain ClojureScript functions.
2013-12-19 12:11:02 +00:00
2014-01-17 10:12:11 +00:00
To use Reagent you add this to your dependencies in `project.clj` :
2013-12-19 13:06:49 +00:00
2014-02-21 15:31:30 +00:00
[reagent "0.4.0"]
2014-01-10 12:59:38 +00:00
You also need to include react.js itself. One way to do this is to add
2014-01-17 10:12:11 +00:00
:preamble ["reagent/react.js"]
2014-01-10 12:59:38 +00:00
to the *:compiler* section of project.clj, as shown in the examples
2014-01-17 10:12:11 +00:00
directory (or "reagent/react.min.js" in production). You could also
2014-01-10 12:59:38 +00:00
add
< script src = "http://fb.me/react-0.8.0.js" > < / script >
directly to your html.
2013-12-19 13:06:49 +00:00
2013-12-19 12:11:02 +00:00
## Examples
2014-01-17 10:12:11 +00:00
Reagent uses [Hiccup-like ](https://github.com/weavejester/hiccup ) markup instead of React's sort-of html. It looks like this:
2013-12-19 12:11:02 +00:00
```clj
(defn some-component []
[:div
[:h3 "I am a component!"]
[:p.someclass
"I have " [:strong "bold"]
[:span {:style {:color "red"}} " and red"]
" text."]])
```
2014-01-07 18:45:41 +00:00
You can use one component inside another:
2013-12-19 12:11:02 +00:00
```clj
(defn calling-component []
[:div "Parent component"
[some-component]])
```
And pass properties from one component to another:
```clj
(defn child [props]
[:p "Hi, I am "
(:name props)])
(defn childcaller []
[child {:name "Foo"}])
```
You mount the component into the DOM like this:
```clj
(defn mountit []
2014-01-17 10:12:11 +00:00
(reagent/render-component [childcaller]
(.-body js/document)))
2013-12-19 12:11:02 +00:00
```
2014-01-17 10:12:11 +00:00
assuming we have imported Reagent like this:
2013-12-19 12:11:02 +00:00
```clj
2014-01-07 18:45:41 +00:00
(ns example
2014-01-17 10:12:11 +00:00
(:require [reagent.core :as reagent :refer [atom]]))
2013-12-19 12:11:02 +00:00
```
2014-01-17 10:12:11 +00:00
State is handled using Reagent's version of `atom` , like this:
2013-12-19 12:11:02 +00:00
```clj
2014-01-07 18:45:41 +00:00
(def click-count (atom 0))
2013-12-19 12:11:02 +00:00
(defn state-ful-with-atom []
[:div {:on-click #(swap! click-count inc)}
"I have been clicked " @click -count " times."])
```
2014-01-17 10:12:11 +00:00
Any component that dereferences a `reagent.core/atom` will be automatically re-rendered.
2013-12-19 12:11:02 +00:00
If you want do some setting up when the component is first created, the component function can return a new function that will be called to do the actual rendering:
```clj
2014-01-07 18:45:41 +00:00
(defn timer-component []
(let [seconds-elapsed (atom 0)]
(fn []
(js/setTimeout #(swap! seconds-elapsed inc) 1000)
[:div
"Seconds Elapsed: " @seconds -elapsed])))
2013-12-19 12:11:02 +00:00
```
This way you can avoid using React's lifecycle callbacks like `getInitialState` and `componentWillMount` most of the time.
2014-01-17 10:12:11 +00:00
But you can still use them if you want to, either using `reagent.core/create-class` or by attaching meta-data to a component function:
2013-12-19 12:11:02 +00:00
```clj
2014-01-07 18:45:41 +00:00
(def my-html (atom ""))
2013-12-19 12:11:02 +00:00
(defn plain-component [props this]
2014-01-07 18:45:41 +00:00
[:p "My html is " @my -html])
2013-12-19 12:11:02 +00:00
(def component-with-callback
(with-meta plain-component
{:component-did-mount
(fn [this]
2014-01-17 10:12:11 +00:00
(reset! my-html (.-innerHTML (reagent/dom-node this))))}))
2013-12-19 12:11:02 +00:00
```
See the examples directory for more examples.
## Performance
2014-01-17 10:12:11 +00:00
React is pretty darn fast, and so is Reagent. It should even be faster than plain old javascript React a lot of the time, since ClojureScript allows us to skip a lot of unnecessary rendering (through judicious use of React's `shouldComponentUpdate` ).
2013-12-19 12:11:02 +00:00
The ClojureScript overhead is kept down, thanks to lots of caching.
2014-01-10 12:59:38 +00:00
Code size is a little bigger than React.js, but still quite small. The todomvc example clocks in at roughly 53K gzipped, using advanced compilation.
2013-12-19 12:11:02 +00:00
## About
The idea and some of the code for making components atom-like comes from [pump ](https://github.com/piranha/pump ). The reactive-atom idea (and some code) comes from [reflex ](https://github.com/lynaghk/reflex ).
The license is MIT.