News in 0.6.0-alpha
Reagent 0.6.0-alpha contains new reactivity helpers, better
    integration with native React components, a new version of
    React (0.14.3), new React dependencies (react-dom
    and react-dom-server), better performance, and much
    more. 
This is a quite big release, so it probably contains a fair amount of bugs as well…
Breaking changes
- Reagent now depends on cljsjs/react-domandcljsjs/react-dom-server(see below).
- The javascript interop macros .'and.!, in thereagent.interopnamespace are now called$and$!respectively (the old names clashed with bootstrapped ClojureScript).
- Reactions, i.e cursorcalled with a function,reagent.ratom/reaction,reagent.ratom/run!andreagent.ratom/make-reactionare now lazy and executed asynchronously. Previously, reactions used to execute immediately whenever the atoms they depended on changed. This could cause performance issues in code with expensive reactions and frequent updates to state. However, this change may break existing code that depends on the timing of side-effects from running reactions.flushcan be used to force outstanding reactions to run at a given time.
- Reactions now only trigger updates of dependent
         components and other reactions if they produce a new result,
         compared with =. Previously,identical?was used.
- next-tickis now guaranteed to execute its argument before the next render (more on that below.)
track: Use any function as a reactive value
reagent.core/track takes a function, and
       optional arguments for that function, and gives a
       derefable (i.e ”atom-like”) value, containing whatever is
       returned by that function. If the tracked function depends on a
       Reagent atom, it is called again whenever that atom changes –
       just like a Reagent component function. If the value returned
       by track is used in a component, the component is
       re-rendered when the value returned by the function changes. 
In other words, @(r/track foo x) gives the
       same result as (foo x) – but in the first case,
       foo is only called again when the atom(s) it depends on
       changes.
Here's an example:
Source
(ns example.core (:require [reagent.core :as r]))(defonce app-state (r/atom {:people {1 {:name "John Smith"} 2 {:name "Maggie Johnson"}}})) (defn people [] (:people @app-state)) (defn person-keys [] (-> @(r/track people) keys sort)) (defn person [id] (-> @(r/track people) (get id))) (defn name-comp [id] (let [p @(r/track person id)] [:li (:name p)])) (defn name-list [] (let [ids @(r/track person-keys)] [:ul (for [i ids] ^{:key i} [name-comp i])]))
Here, the name-list component will only be
       re-rendered if the keys of the :people map
       changes. Every name-comp only renders again when
       needed, etc.
Use of track can improve performance in
       three ways:
- It can be used as a cache for an expensive function, that is automatically updated if that function depends on Reagent atoms (or other tracks, cursors, etc).
- It can also be used to limit the number of times a
        component is re-rendered. The user of trackis only updated when the function’s result changes. In other words, you can use track as a kind of generalized, read-only cursor.
- Every use of trackwith the same arguments will only result in one execution of the function. E.g the two uses of@(r/track people)in the example above will only result in one call to thepeoplefunction (both initially, and when the state atom changes).
If you've been using reagent.ratom/reaction
       etc, track should be quite familiar. The main
       difference is that track uses named functions and
       variables, rather than depending on closures, and that you
       don’t have to manage their creation manually (since tracks are
       automatically cached and reused).
Note: The first argument to track
       should be a named function, i.e not an anonymous one. Also,
       beware of lazy data sequences: don’t use deref (i.e ”@”) with
       the for macro, unless wrapped
       in doall (just like in Reagent components). 
track!
track! is another new function. It works just
       like track, except that the function passed is
       invoked immediately, and continues to be invoked whenever any
       atoms used within it changes.
For example, given this function:
Source
(defn log-app-state [] (prn @app-state))
you could use (defonce logger (r/track!
       log-app-state)) to monitor changes
       to app-state. log-app-state would
       continue to run until you stop it, using (r/dispose!
       logger).
with-let: Handling destruction
Reagent now has a new way of writing components that need
       to do something when they are no longer around:
       the with-let macro. It looks just
       like let – but the bindings only execute once,
       and it takes an optional finally clause, that
       runs when the component is no longer rendered.
For example: here's a component that sets up an event listener for mouse moves, and stops listening when the component is removed.
Source
(defn mouse-pos-comp [] (r/with-let [pointer (r/atom nil) handler #(swap! pointer assoc :x (.-pageX %) :y (.-pageY %)) _ (.addEventListener js/document "mousemove" handler)] [:div "Pointer moved to: " (str @pointer)] (finally (.removeEventListener js/document "mousemove" handler))))
The same thing could of course be achieved with React lifecycle methods, but that would be a lot more verbose.
with-let can also be combined
       with track (and other reactive contexts). For
       example, the component above could be written as: 
Source
(defn mouse-pos [] (r/with-let [pointer (r/atom nil) handler #(swap! pointer assoc :x (.-pageX %) :y (.-pageY %)) _ (.addEventListener js/document "mousemove" handler)] @pointer (finally (.removeEventListener js/document "mousemove" handler)))) (defn tracked-pos [] [:div "Pointer moved to: " (str @(r/track mouse-pos))])
The finally clause will run
       when mouse-pos is no longer tracked anywhere, i.e
       in this case when tracked-posis unmounted.
with-let can also generally be used instead of
       returning functions from components that keep local state, and
       may be a bit easier to read.
Event handling with rswap!
rswap! is another new function in 0.6.0. It
        works like standard swap! except that it
- always returns nil
- allows recursive applications of rswap!on the same atom.
That makes rswap! especially suited for event
        handling.
Here’s an example that uses event handling
        with rswap! to edit the data introduced in the
        section about track above:
Source
(defn event-handler [state [event-name id value]] (case event-name :set-name (assoc-in state [:people id :name] value) :add-person (let [new-key (->> state :people keys (apply max) inc)] (assoc-in state [:people new-key] {:name ""})) state)) (defn emit [e] ;; (js/console.log "Handling event" (str e)) (r/rswap! app-state event-handler e)) (defn name-edit [id] (let [p @(r/track person id)] [:div [:input {:value (:name p) :on-change #(emit [:set-name id (.-target.value %)])}]])) (defn edit-fields [] (let [ids @(r/track person-keys)] [:div [name-list] (for [i ids] ^{:key i} [name-edit i]) [:input {:type 'button :value "Add person" :on-click #(emit [:add-person])}]]))
All events are passed through the emit
        function, consisting of a trivial application
        of rswap! and some optional logging. This is the
        only place where application state actually changes – the rest
        is pure functions.
The actual event handling is done
        in event-handler, which takes state and event as
        parameters, and returns a new state (events are represented by
        vectors here, with an event name in the first position).
All the UI components have to do is then just to return
        some markup, and set up routing of events through the emit
        function. 
This architecture basically divides the application into two logical functions:
- The first takes state and an event as input, and returns the next state.
- The other takes state as input, and returns a UI definition.
This simple application could probably just as well use
        the common swap! instead of rswap!,
        but using swap! in React’s event handlers may
        trigger warnings due to unexpected return values, and may
        cause severe headaches if an event handler called by emit
        itself emits a new event (that would result in lost
        events, and much confusion).
For a more structured version of a similar approach, see the excellent re-frame framework.
New React version and new namespaces
Reagent now depends on React version 0.14.3. React itself is now split into three parts, with separate packages for browser specific code, and HTML generation respectively.
To reflect that, two new namespaces have been introduced
        in Reagent as well: reagent.dom
        and reagent.dom.server. They contain functions
        that used to be in reagent.core. 
reagent.dom contains: 
- render
- unmount-component-at-node
- dom-node
- force-update-all
reagent.dom.server contains: 
- render-to-string
- render-to-static-markup
These functions are still available
        in reagent.core in this release (for backward
        compatibility reasons), but they may be deprecated in the
        future.
The changes in React also mean that if you specify the
        React version to use in your project.clj,
        with cljsjs/react in the :dependencies
        section, you now have to specify cljsjs/react-dom
        and cljsjs/react-dom-server instead.
Better interop with native React
The output of create-class can now be used
        directly in JSX.
”Native React components” can now be used directly in
        Reagent’s hiccup forms, using this syntax: [:>
        nativeComp {:key "value"}]. This might sometimes be more
        convenient than using adapt-react-class. 
Reagent should now also be a bit easier to use in
        node.js. If global React is not
        defined (i.e React, ReactDOM
        and ReactDOMServer), Reagent tries to
        use require instead, to get react, react-dom and
        react-dom/server from npm.
Better cursor
Cursors are now cached, which should make them a bit
        easier to use. Previously, every instance
        of cursor had its own state.
        Now cursors called with the same arguments share
        data, which means that components like this now make sense: 
Source
(defn cursor-example [] (let [first-person (r/cursor app-state [:people 1])] [:p "A person: " (:name @first-person)]))
Previously cursors were really only useful (in the sense that unnecessary re-renderings were avoided) when passed as arguments to child components.
Tapping into the rendering loop
The next-tick function now has a more
        predictable timing. The function passed
        to next-tick is now invoked immediately before the
        next rendering (which is in turn triggered
        using requestAnimationFrame).
after-update works just
        like next-tick, except that the function given is
        invoked immediately after the next rendering.
