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-dom
and cljsjs/react-dom-server (see below).

The javascript interop macros .'
and .!, in the reagent.interop
namespace are now called $ and $!
respectively (the old names clashed with bootstrapped
ClojureScript).

Reactions, i.e cursor called with a
function, reagent.ratom/reaction, reagent.ratom/run!
and reagent.ratom/make-reaction are 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. flush can 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-tick is 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, 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 track is
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 track with 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 the people
function (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

(defnlog-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.

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:

Example

Source

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.