2013-12-19 13:11:02 +01:00
2014-01-17 11:12:11 +01:00
# Reagent
2013-12-19 13:11:02 +01:00
2018-11-14 23:38:13 +02:00
![Reagent-Project ](logo.png )
2018-09-11 15:53:44 +02:00
2014-11-06 20:21:38 +01:00
A simple [ClojureScript ](http://github.com/clojure/clojurescript ) interface to [React ](http://facebook.github.io/react/ ).
2014-02-22 14:12:01 +07:00
Reagent provides a way to write efficient React components using (almost) nothing but plain ClojureScript functions.
2014-11-28 08:51:22 -08:00
* **[Detailed intro with live examples ](http://reagent-project.github.io/ )**
* **[News ](http://reagent-project.github.io/news/index.html )**
2020-02-03 10:11:12 +02:00
* **[Documentation, 0.9 ](https://cljdoc.org/d/reagent/reagent/0.9.1/doc/documentation-index )**
* **Documentation, next release**
2019-11-24 16:24:21 +02:00
* **[API docs ](http://reagent-project.github.io/docs/master/ )**
* **[Tutorials and FAQ ](https://github.com/reagent-project/reagent/tree/master/doc )**
2017-05-15 10:41:12 +03:00
* **Community discussion and support channels**
* **[#reagent ](https://clojurians.slack.com/messages/reagent/ )** channel in [Clojure Slack ](http://clojurians.net/ )
* **[Reagent Project Mailing List ](https://groups.google.com/forum/#!forum/reagent-project )**
2018-06-27 12:02:15 +03:00
* **Commercial video material**
2018-06-27 12:47:42 +03:00
* [Learn Reagent Free ](https://www.jacekschae.com/learn-reagent-free/tycit?coupon=REAGENT )
* [Learn Reagent Pro ](https://www.jacekschae.com/learn-reagent-pro/tycit?coupon=REAGENT ) (Affiliate link, $30 discount)
2019-05-08 17:17:34 +03:00
* [Learn Re-frame Free ](https://www.jacekschae.com/learn-re-frame-free/tycit?coupon=REAGENT )
* [Learn Re-frame Pro ](https://www.jacekschae.com/learn-re-frame-pro/tycit?coupon=REAGENT ) (Affiliate link, $30 discount)
2018-06-27 12:02:15 +03:00
* [purelyfunctional.tv ](https://purelyfunctional.tv/guide/reagent/ )
* [Lambda Island Videos ](https://lambdaisland.com/collections/react-reagent-re-frame )
2013-12-19 13:11:02 +01:00
2016-02-27 20:58:20 -05:00
### Usage
2019-08-13 09:37:03 +03:00
To create a new Reagent project using [Leiningen ](http://leiningen.org/ ) template simply run:
2014-12-02 11:22:13 -05:00
lein new reagent myproject
2016-02-16 18:32:36 -05:00
If you wish to only create the assets for ClojureScript without a Clojure backend then do the following instead:
lein new reagent-frontend myproject
2018-06-27 12:02:15 +03:00
This will setup a new Reagent project with some reasonable defaults, see here for more [details ](https://github.com/reagent-project/reagent-template ).
2014-12-02 11:22:13 -05:00
To use Reagent in an existing project you add this to your dependencies in `project.clj` :
2013-12-19 14:06:49 +01:00
2016-10-26 11:08:54 +11:00
[![Clojars Project ](http://clojars.org/reagent/latest-version.svg )](http://clojars.org/reagent) < br >
2016-10-26 11:08:05 +11:00
[![CircleCI ](https://circleci.com/gh/reagent-project/reagent.svg?style=svg )](https://circleci.com/gh/reagent-project/reagent)
2014-01-10 13:59:38 +01:00
2019-03-03 14:36:10 +02:00
This is all you need to do if you want the standard version of React. If you want to use your own build of React (or React from a CDN), you have to use `:exclusions` variant of the dependency, and also provide `react` and `react-dom` namespaces (by creating `.cljs` files with just `ns` form, or by adding your own `:foreign-libs` entries).
2014-01-10 13:59:38 +01:00
2019-01-31 20:39:21 +02:00
[reagent "0.x.x" :exclusions [cljsjs/react cljsjs/react-dom]]
2013-12-19 14:06:49 +01:00
2013-12-19 13:11:02 +01:00
## Examples
2014-01-17 11:12:11 +01: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 13:11:02 +01:00
```clj
(defn some-component []
[:div
[:h3 "I am a component!"]
2018-06-27 12:02:15 +03:00
[:p.someclass
2013-12-19 13:11:02 +01:00
"I have " [:strong "bold"]
[:span {:style {:color "red"}} " and red"]
" text."]])
```
2015-06-25 08:39:10 -07:00
Reagent extends standard Hiccup in one way: it is possible to "squeeze" elements together by using a `>` character.
```clj
[:div
[:p
[:b "Nested Element"]]]
```
2018-06-27 12:02:15 +03:00
2015-06-25 08:39:10 -07:00
can be written as:
2018-06-27 12:02:15 +03:00
2015-06-25 08:39:10 -07:00
```clj
[:div>p>b "Nested Element"]
2018-06-27 12:02:15 +03:00
```
2015-06-25 08:39:10 -07:00
2018-01-08 18:36:18 +02:00
> **Since version 0.8:** The `:class` attribute also supports collections of classes, and nil values are removed:
2018-06-27 12:02:15 +03:00
>
2018-01-08 18:36:18 +02:00
> ```clj
> [:div {:class ["a-class" (when active? "active") "b-class"]}]
> ```
2015-07-02 18:12:48 +02:00
2014-01-07 19:45:41 +01:00
You can use one component inside another:
2013-12-19 13:11:02 +01:00
```clj
(defn calling-component []
[:div "Parent component"
[some-component]])
```
And pass properties from one component to another:
```clj
2014-02-21 17:16:26 +01:00
(defn child [name]
[:p "Hi, I am " name])
2013-12-19 13:11:02 +01:00
(defn childcaller []
2014-02-21 17:16:26 +01:00
[child "Foo Bar"])
2013-12-19 13:11:02 +01:00
```
You mount the component into the DOM like this:
```clj
(defn mountit []
2017-03-10 17:19:19 +02:00
(r/render [childcaller]
(.-body js/document)))
2013-12-19 13:11:02 +01:00
```
2014-01-17 11:12:11 +01:00
assuming we have imported Reagent like this:
2013-12-19 13:11:02 +01:00
```clj
2014-01-07 19:45:41 +01:00
(ns example
2015-07-31 16:18:17 +10:00
(:require [reagent.core :as r]))
2013-12-19 13:11:02 +01:00
```
2014-01-17 11:12:11 +01:00
State is handled using Reagent's version of `atom` , like this:
2013-12-19 13:11:02 +01:00
```clj
2015-08-08 01:33:19 +10:00
(defonce click-count (r/atom 0))
2013-12-19 13:11:02 +01:00
(defn state-ful-with-atom []
[:div {:on-click #(swap! click-count inc)}
"I have been clicked " @click -count " times."])
```
2014-01-17 11:12:11 +01:00
Any component that dereferences a `reagent.core/atom` will be automatically re-rendered.
2013-12-19 13:11:02 +01: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 19:45:41 +01:00
(defn timer-component []
2015-07-31 16:18:17 +10:00
(let [seconds-elapsed (r/atom 0)]
2014-01-07 19:45:41 +01:00
(fn []
(js/setTimeout #(swap! seconds-elapsed inc) 1000)
[:div
"Seconds Elapsed: " @seconds -elapsed])))
2013-12-19 13:11:02 +01:00
```
This way you can avoid using React's lifecycle callbacks like `getInitialState` and `componentWillMount` most of the time.
2014-01-17 11:12:11 +01: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 13:11:02 +01:00
```clj
2015-08-08 01:33:19 +10:00
(defonce my-html (r/atom ""))
2014-01-07 19:45:41 +01:00
2014-02-21 17:16:26 +01:00
(defn plain-component []
2014-01-07 19:45:41 +01:00
[:p "My html is " @my -html])
2013-12-19 13:11:02 +01:00
(def component-with-callback
(with-meta plain-component
{:component-did-mount
(fn [this]
2014-01-17 11:12:11 +01:00
(reset! my-html (.-innerHTML (reagent/dom-node this))))}))
2013-12-19 13:11:02 +01:00
```
See the examples directory for more examples.
## Performance
2014-01-17 11:12:11 +01: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 13:11:02 +01:00
The ClojureScript overhead is kept down, thanks to lots of caching.
2018-02-20 18:04:24 -08:00
Code size is a little bigger than React.js, but still quite small. The todomvc example clocks in at roughly 79K gzipped, using advanced compilation.
2013-12-19 13:11:02 +01: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.