2016-12-06 22:57:20 +00:00
## Initial Code Walk-through
2017-04-15 02:19:24 +00:00
At this point, you are about 55% of the way to understanding re-frame. You have:
2016-12-29 07:01:12 +00:00
- an overview of the 6 domino process [from this repo's README ](../README.md )
2017-01-02 00:50:28 +00:00
- an understanding of app state ([from the previous tutorial](ApplicationState.md))
2016-12-06 22:57:20 +00:00
2017-04-15 02:19:24 +00:00
In this tutorial, **we look at re-frame code** . By the end of it, you'll be at 70% knowledge, and ready to start coding an app.
2016-12-11 12:46:55 +00:00
2016-12-04 03:20:25 +00:00
## What Code?
2016-10-20 20:07:38 +00:00
2017-09-12 04:37:28 +00:00
This repo contains an `/examples` application called ["simple" ](https://github.com/Day8/re-frame/tree/master/examples/simple ),
which contains 70 lines of code. We'll look at every line of [the file ](https://github.com/Day8/re-frame/blob/master/examples/simple/src/simple/core.cljs ).
2016-10-20 20:07:38 +00:00
2016-10-21 05:08:16 +00:00
This app:
2016-12-06 22:57:20 +00:00
- displays the current time in a nice big, colourful font
2016-12-11 12:46:55 +00:00
- provides a single text input field, into which you can type a hex colour code,
like "#CCC", used for the time display
2016-10-21 05:08:16 +00:00
2016-12-29 00:05:15 +00:00
When it is running, here's what it looks like:
2016-12-18 22:41:21 +00:00
2016-12-07 23:29:45 +00:00
![Example App image ](../images/example_app.png )
2016-10-20 20:07:38 +00:00
2016-12-29 07:01:12 +00:00
To run the code yourself:
2016-12-11 12:46:55 +00:00
* Install Java 8
2016-12-07 22:56:18 +00:00
* Install leiningen (http://leiningen.org/#install)
2016-12-06 22:57:20 +00:00
2016-12-07 22:56:18 +00:00
Then:
2016-12-11 12:46:55 +00:00
1. `git clone https://github.com/Day8/re-frame.git`
2. `cd re-frame/examples/simple`
3. `lein do clean, figwheel`
2017-07-13 13:08:30 +00:00
4. wait a minute and then open < http: // localhost:3449 / example . html >
2016-12-29 07:01:12 +00:00
2017-04-15 02:19:24 +00:00
So, what's just happened? The ClojureScript code under `/src` has been compiled into `javascript` and
put into `/resources/public/js/client.js` which is loaded into `/resources/public/example.html` (the HTML you just opened)
2016-12-29 07:01:12 +00:00
2017-04-15 02:19:24 +00:00
Figwheel provides for hot-loading, so you can edit the source code (under `/src` )and watch the loaded HTML change.
2016-10-20 20:07:38 +00:00
2016-10-21 12:12:24 +00:00
2016-12-04 03:20:25 +00:00
## Namespace
2016-10-20 20:07:38 +00:00
2017-04-15 02:19:24 +00:00
Because this example is tiny, the source code is in a single namespace:
2016-12-17 01:52:32 +00:00
https://github.com/Day8/re-frame/blob/master/examples/simple/src/simple/core.cljs
2016-12-11 12:46:55 +00:00
Within this namespace, we'll need access to both `reagent` and `re-frame` .
So, at the top, we start like this:
2016-10-20 20:07:38 +00:00
```clj
(ns simple.core
(:require [reagent.core :as reagent]
[re-frame.core :as rf]))
```
2016-12-04 03:20:25 +00:00
## Data Schema
2016-10-20 20:07:38 +00:00
2017-04-15 02:19:24 +00:00
Now, normally, I'd strongly recommended that you write a quality schema
2016-10-22 03:56:04 +00:00
for your application state (the data stored in `app-db` ). But,
2017-02-02 19:58:58 +00:00
here, to minimise cognitive load, we'll cut that corner.
2016-10-20 20:07:38 +00:00
2016-11-30 10:28:01 +00:00
But ... we can't cut it completely. You'll still need an
2016-12-03 20:57:31 +00:00
informal description, and here it is ... for this app `app-db` will contain
2016-10-22 03:56:04 +00:00
a two-key map like this:
2017-09-28 12:26:27 +00:00
```clj
2016-12-03 20:57:31 +00:00
{:time (js/Date.) ;; current time for display
2017-08-14 19:50:02 +00:00
:time-color "#f88"} ;; the colour in which the time should be shown
2016-10-20 20:07:38 +00:00
```
2016-12-03 20:57:31 +00:00
re-frame itself owns/manages `app-db` (see FAQ #1 ), and it will
2017-04-15 02:19:24 +00:00
supply the value within it (the two-key map described above)
2016-10-22 03:56:04 +00:00
to your various handlers as required.
2016-10-20 20:07:38 +00:00
## Events (domino 1)
2016-12-29 00:05:15 +00:00
Events are data.
2016-10-20 20:07:38 +00:00
2016-12-05 01:42:09 +00:00
re-frame uses a vector
2016-10-20 20:07:38 +00:00
format for events. For example:
```clj
[:delete-item 42]
```
2017-01-16 03:26:47 +00:00
The first element in the vector is a keyword which identifies the `kind` of `event` . The
2016-10-21 12:12:24 +00:00
further elements are optional, and can provide additional data
2016-10-22 03:56:04 +00:00
associated with the event. The additional value above, `42` , is
presumably the id of the item to delete.
2016-10-20 20:07:38 +00:00
2016-12-04 23:49:04 +00:00
Here are some other example events:
2016-10-20 20:07:38 +00:00
```clj
2016-12-14 14:24:37 +00:00
[:admit-to-being-satoshi false]
2016-12-23 09:52:18 +00:00
[:dressing/put-pants-on "velour flares" {:method :left-leg-first :belt false}]
2016-10-20 20:07:38 +00:00
```
2017-01-16 03:26:47 +00:00
(For non-trivial applications, the `kind` keyword will be namespaced.)
2016-10-22 00:57:35 +00:00
2016-11-30 10:28:01 +00:00
**Rule**: events are pure data. No sneaky tricks like putting
2016-10-21 12:12:24 +00:00
callback functions on the wire. You know who you are.
2016-10-20 20:07:38 +00:00
### dispatch
2016-10-22 03:56:04 +00:00
To send an event, call `dispatch` with the event vector as argument:
2016-10-20 20:07:38 +00:00
```clj
2016-12-17 01:52:32 +00:00
(rf/dispatch [:event-id value1 value2])
2016-10-20 20:07:38 +00:00
```
2016-12-14 14:24:37 +00:00
In this "simple" app, a `:timer` event is dispatched every second:
2016-10-20 20:07:38 +00:00
```clj
(defn dispatch-timer-event
[]
(let [now (js/Date.)]
2016-10-22 03:56:04 +00:00
(rf/dispatch [:timer now]))) ;; < -- dispatch used
2016-10-20 20:07:38 +00:00
;; call the dispatching function every second
2016-10-22 03:56:04 +00:00
(defonce do-timer (js/setInterval dispatch-timer-event 1000))
2016-10-20 20:07:38 +00:00
```
2016-10-22 03:56:04 +00:00
This is an unusual source of events. Normally, it is an app's UI widgets which
2016-10-20 20:07:38 +00:00
`dispatch` events (in response to user actions), or an HTTP POST's
2016-10-22 03:56:04 +00:00
`on-success` handler, or a websocket which gets a new packet.
2016-10-20 20:07:38 +00:00
### After dispatch
2016-10-22 00:57:35 +00:00
`dispatch` puts an event into a queue for processing.
2016-10-20 20:07:38 +00:00
2016-11-30 10:28:01 +00:00
So, **an event is not processed synchronously, like a function call** . The processing
2016-10-21 12:12:24 +00:00
happens **later** - asynchronously. Very soon, but not now.
2016-10-20 20:07:38 +00:00
2016-10-22 00:57:35 +00:00
The consumer of the queue is a `router` which looks after the event's processing.
2016-10-20 20:07:38 +00:00
2016-10-21 05:08:16 +00:00
The `router` :
2016-12-04 23:49:04 +00:00
2016-10-21 12:12:24 +00:00
1. inspects the 1st element of an event vector
2017-04-15 02:19:24 +00:00
2. looks for the event handler (function) which is **registered**
2016-10-21 12:12:24 +00:00
for this kind of event
2016-10-22 03:56:04 +00:00
3. calls that event handler with the necessary arguments
2016-10-21 05:08:16 +00:00
2017-04-15 02:19:24 +00:00
As a re-frame app developer, your job, then, is to write and register an
event handler (function) for each kind of event.
2016-10-20 20:07:38 +00:00
## Event Handlers (domino 2)
Collectively, event handlers provide the control logic in a re-frame application.
2016-12-04 23:49:04 +00:00
In this application, 3 kinds of event are dispatched:
2017-01-16 03:26:47 +00:00
`:initialize`
2016-10-21 05:08:16 +00:00
`:time-color-change`
`:timer`
2017-01-16 03:24:00 +00:00
3 events means we'll be registering 3 event handlers.
2016-10-21 05:08:16 +00:00
2017-01-16 03:26:47 +00:00
### Two ways to register
2016-12-14 14:24:37 +00:00
2017-04-15 02:19:24 +00:00
Event handler functions take two arguments `coeffects` and `event` ,
and they return `effects` .
2016-12-14 14:24:37 +00:00
2017-04-15 02:19:24 +00:00
Conceptually, you can think of `coeffects` as being "the current state of the world".
And you can think of event handlers has computing and returning changes (effects) based on
"the current state of the world" and the arriving event.
Event handlers can be registered via either `reg-event-fx`
2017-01-16 03:26:47 +00:00
or `reg-event-db` (`-fx` vs `-db` ):
- `reg-event-fx` can take multiple `coeffects` and can return multiple `effects` , while
2017-04-15 02:19:24 +00:00
- `reg-event-db` allows you to write simpler handlers for the common case where you want
2017-01-16 03:26:47 +00:00
them to take only one `coeffect` - the current app state - and return one `effect` - the
updated app state.
2016-12-14 14:24:37 +00:00
2017-04-15 02:19:24 +00:00
Because of its simplicity, we'll be using the latter here: `reg-event-db` .
2016-12-14 14:24:37 +00:00
2016-10-21 05:08:16 +00:00
### reg-event-db
2016-10-20 20:07:38 +00:00
2017-01-16 03:26:47 +00:00
We register event handlers using re-frame's `reg-event-db` :
2016-10-20 20:07:38 +00:00
```clj
2016-12-17 01:52:32 +00:00
(rf/reg-event-db
2016-10-22 00:57:35 +00:00
:the-event-id
the-event-handler-fn)
2016-10-20 20:07:38 +00:00
```
2017-01-16 03:26:47 +00:00
The handler function you provide should expect two arguments:
- `db` , the current application state (the value contained in `app-db` )
2017-04-15 02:19:24 +00:00
- `v` , the event vector (what was given to `dispatch` )
2016-10-21 05:08:16 +00:00
2017-04-15 02:19:24 +00:00
So, your function will have a signature like this: `(fn [db v] ...)` .
2016-10-21 05:08:16 +00:00
2017-04-15 02:19:24 +00:00
Each event handler must compute and return the new state of
2017-01-16 03:26:47 +00:00
the application, which means it returns a
2017-04-15 02:19:24 +00:00
modified version of `db` (or an unmodified one, if there are to be no changes to the state).
2016-10-20 20:07:38 +00:00
2016-10-22 00:57:35 +00:00
### :initialize
2017-01-16 03:26:47 +00:00
On startup, application state must be initialized. We
want to put a sensible value into `app-db` , which starts out containing `{}` .
2016-10-22 00:57:35 +00:00
So a `(dispatch [:initialize])` will happen early in the
2017-01-16 03:26:47 +00:00
app's life (more on this below), and we need to write an `event handler`
2016-10-22 00:57:35 +00:00
for it.
2017-01-16 03:26:47 +00:00
Now this event handler is slightly unusual because not only does it not care about
any event information passed in via the `event` vector, but it doesn't
even care about the existing value in `db` - it just wants to plonk
a completely new value:
2016-10-20 20:07:38 +00:00
```clj
(rf/reg-event-db ;; sets up initial application state
2017-01-16 03:24:00 +00:00
:initialize
2016-10-20 20:07:38 +00:00
(fn [_ _] ;; the two parameters are not important here, so use _
{:time (js/Date.) ;; What it returns becomes the new application state
:time-color "#f88"})) ;; so the application state will initially be a map with two keys
2016-10-21 05:08:16 +00:00
```
2016-10-20 20:07:38 +00:00
2016-10-21 12:12:24 +00:00
This particular handler `fn` ignores the two parameters
2016-11-30 10:28:01 +00:00
(usually called `db` and `v` ) and simply returns
2016-10-21 12:12:24 +00:00
a map literal, which becomes the application
2016-10-22 00:57:35 +00:00
state.
2016-10-20 20:07:38 +00:00
2017-01-16 03:26:47 +00:00
For comparison, here's how we would have written this if we'd cared about the existing value of `db` :
2016-10-22 00:57:35 +00:00
```clj
(rf/reg-event-db
2017-01-16 03:24:00 +00:00
:initialize
(fn [db _] ;; we use db this time, so name it
(-> db
2016-10-22 00:57:35 +00:00
(assoc :time (js/Date.))
(assoc :time-color "#f88")))
```
2016-10-20 20:07:38 +00:00
2016-10-22 00:57:35 +00:00
### :timer
2016-10-20 20:07:38 +00:00
2016-11-30 10:28:01 +00:00
Earlier, we set up a timer function to `(dispatch [:timer now])` every second.
2016-10-22 00:57:35 +00:00
Here's how we handle it:
2016-10-21 05:08:16 +00:00
```clj
2016-12-17 01:52:32 +00:00
(rf/reg-event-db ;; usage: (rf/dispatch [:timer a-js-Date])
2017-01-16 03:24:00 +00:00
:timer
2016-10-21 05:08:16 +00:00
(fn [db [_ new-time]] ;; < -- de-structure the event vector
2016-10-20 20:07:38 +00:00
(assoc db :time new-time))) ;; compute and return the new application state
```
2016-10-21 05:08:16 +00:00
Notes:
2016-10-22 00:57:35 +00:00
1. the `event` will be like `[:timer a-time]` , so the 2nd `v` parameter
destructures to extract the `a-time` value
2016-10-21 12:12:24 +00:00
2. the handler computes a new application state from `db` , and returns it
2016-10-21 05:08:16 +00:00
2016-10-22 00:57:35 +00:00
### :time-color-change
2016-10-21 05:08:16 +00:00
When the user enters a new colour value (via an input text box):
```clj
2017-01-16 03:24:00 +00:00
(rf/reg-event-db
2016-12-17 01:52:32 +00:00
:time-color-change ;; usage: (rf/dispatch [:time-color-change 34562])
2017-01-16 03:24:00 +00:00
(fn [db [_ new-color-value]]
2016-10-21 05:08:16 +00:00
(assoc db :time-color new-color-value))) ;; compute and return the new application state
```
2016-10-20 20:07:38 +00:00
## Effect Handlers (domino 3)
2017-02-02 19:58:58 +00:00
Domino 3 realises/puts into action the `effects` returned by event handlers.
2016-10-20 20:07:38 +00:00
2016-10-22 00:57:35 +00:00
In this "simple" application, our event handlers are implicitly returning
2016-12-03 10:44:06 +00:00
only one effect: "update application state".
2016-10-20 20:07:38 +00:00
2017-01-16 03:26:47 +00:00
This particular `effect` is accomplished by a re-frame-supplied
`effect` handler. **So, there's nothing for us to do for this domino** . We are
2016-12-03 10:44:06 +00:00
using a standard re-frame effect handler.
2016-10-20 20:07:38 +00:00
2017-01-16 03:26:47 +00:00
And this is not unusual. You'll seldom have to write `effect` handlers, but in a later
tutorial we'll show you more about how to do so when you need to.
2016-10-20 20:07:38 +00:00
## Subscription Handlers (domino 4)
2017-01-16 03:26:47 +00:00
Subscription handlers, or `query` functions, take application state as an argument
and run a query over it, returning something called
2017-02-02 19:58:58 +00:00
a "materialised view" of that application state.
2016-10-21 12:12:24 +00:00
2016-12-03 10:44:06 +00:00
When the application state changes, subscription functions are
2017-04-15 02:19:24 +00:00
re-run by re-frame, to compute new values (new materialised views).
2016-10-22 00:57:35 +00:00
2016-12-03 10:44:06 +00:00
Ultimately, the data returned by `query` functions is used
2017-04-15 02:19:24 +00:00
in the `view` functions (Domino 5).
2016-12-03 10:44:06 +00:00
2016-12-04 03:20:25 +00:00
One subscription can
source data from other subscriptions. So it is possible to
2017-04-15 02:19:24 +00:00
create a tree of dependencies.
2016-12-04 03:20:25 +00:00
2017-01-16 03:26:47 +00:00
The Views (Domino 5) are the leaves of this tree. The tree's
2016-12-04 03:20:25 +00:00
root is `app-db` and the intermediate nodes between the two
are computations being performed by the query functions of Domino 4.
Now, the two examples below are trivial. They just extract part of the application
state and return it. So, there's virtually no computation. A more interesting tree
2017-01-16 03:26:47 +00:00
of subscriptions, and more explanation, can be found in the todomvc example.
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
### reg-sub
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
`reg-sub` associates a `query id` with a function that computes
that query, like this:
2016-10-20 20:07:38 +00:00
```clj
2016-12-17 01:52:32 +00:00
(rf/reg-sub
2016-12-03 20:57:31 +00:00
:some-query-id ;; query id (used later in subscribe)
a-query-fn) ;; the function which will compute the query
2016-10-20 20:07:38 +00:00
```
2017-04-15 02:19:24 +00:00
Then later, a view function (domino 5) subscribes to a query like this:
2017-01-16 03:26:47 +00:00
`(subscribe [:some-query-id])` , and `a-query-fn` will be used
to perform the query over the application state.
2016-10-20 20:07:38 +00:00
2016-12-03 20:57:31 +00:00
Each time application state changes, `a-query-fn` will be
2017-02-02 19:58:58 +00:00
called again to compute a new materialised view (a new computation over app state)
2017-01-16 03:26:47 +00:00
and that new value will be given to all `view` functions which are subscribed
to `:some-query-id` . These `view` functions will then be called to compute the
new DOM state (because the views depend on query results which have changed).
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
Along this reactive chain of dependencies, re-frame will ensure the
necessary calls are made, at the right time.
2016-10-21 12:12:24 +00:00
2016-10-22 00:57:35 +00:00
Here's the code:
2016-10-20 20:07:38 +00:00
```clj
(rf/reg-sub
:time
2016-10-21 12:12:24 +00:00
(fn [db _] ;; db is current app state. 2nd unused param is query vector
2016-10-20 20:07:38 +00:00
(:time db))) ;; return a query computation over the application state
(rf/reg-sub
:time-color
(fn [db _]
(:time-color db)))
```
2017-04-15 02:19:24 +00:00
Like I said, both of these queries are trivial.
See [todomvc.subs.clj ](https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/subs.cljs )
for more interesting ones.
2016-10-20 20:07:38 +00:00
## View Functions (domino 5)
2017-04-15 02:19:24 +00:00
`view` functions turn data into DOM. They are "State in, Hiccup out" and they are Reagent
components.
2016-10-20 20:07:38 +00:00
2017-04-15 02:19:24 +00:00
An SPA will have lots of `view` functions, and collectively,
2016-12-03 10:44:06 +00:00
they render the app's entire UI.
2016-12-04 03:20:25 +00:00
### Hiccup
2016-10-21 12:12:24 +00:00
2016-12-04 23:49:04 +00:00
`Hiccup` is a data format for representing HTML.
2016-12-04 03:20:25 +00:00
Here's a trivial view function which returns hiccup-formatted data:
2017-01-16 03:26:47 +00:00
```clj
2016-10-21 09:40:32 +00:00
(defn greet
[]
2016-12-03 10:44:06 +00:00
[:div "Hello viewers"]) ;; means < div > Hello viewers< / div >
2016-10-21 09:40:32 +00:00
```
And if we call it:
```clj
(greet)
;; ==> [:div "Hello viewers"]
2016-12-03 10:44:06 +00:00
(first (greet))
;; ==> :div
2016-10-21 09:40:32 +00:00
```
2016-12-04 03:20:25 +00:00
Yep, that's a vector with two elements: a keyword and a string.
2016-12-03 10:44:06 +00:00
2017-01-16 03:26:47 +00:00
Now, `greet` is pretty simple because it only has the "Hiccup Out" part. There's no "Data In".
2016-10-21 12:12:24 +00:00
2016-12-04 03:20:25 +00:00
### Subscribing
2016-10-21 09:40:32 +00:00
2017-01-16 03:26:47 +00:00
To render the DOM representation of some part of the app state, view functions must query
2016-12-04 03:20:25 +00:00
for that part of `app-db` , and that means using `subscribe` .
2016-12-03 20:57:31 +00:00
2016-12-04 03:20:25 +00:00
`subscribe` is always called like this:
```Clojure
2016-12-17 01:52:32 +00:00
(rf/subscribe [query-id some optional query parameters])
2016-12-04 03:20:25 +00:00
```
There's only one (global) `subscribe` function and it takes one argument, assumed to be a vector.
2016-10-20 20:07:38 +00:00
2017-01-16 03:26:47 +00:00
The first element in the vector (shown above as `query-id` ) identifies the query,
2016-12-04 03:20:25 +00:00
and the other elements are optional
query parameters. With a traditional database a query might be:
```
select * from customers where name="blah"
```
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
In re-frame, that would be done as follows:
2017-01-16 03:26:47 +00:00
`(subscribe [:customer-query "blah"])` ,
2016-12-04 03:20:25 +00:00
which would return a `ratom` holding the customer state (a value which might change over time!).
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
> Because subscriptions return a ratom, they must always be dereferenced to
obtain the value. This is a recurring trap for newbies.
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
### The View Functions
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
This view function renders the clock:
2016-10-20 20:07:38 +00:00
```clj
(defn clock
[]
[:div.example-clock
2016-10-24 03:21:47 +00:00
{:style {:color @(rf/subscribe [:time-color])}}
2016-12-04 03:20:25 +00:00
(-> @(rf/subscribe [:time])
2016-10-20 20:07:38 +00:00
.toTimeString
(clojure.string/split " ")
first)])
2016-12-04 03:20:25 +00:00
```
As you can see, it uses `subscribe` twice to obtain two pieces of data from `app-db` .
If either change, re-frame will re-run this view function.
2016-10-20 20:07:38 +00:00
2016-12-04 03:20:25 +00:00
And this view function renders the input field:
```clj
2016-10-20 20:07:38 +00:00
(defn color-input
[]
[:div.color-input
"Time color: "
[:input {:type "text"
2016-12-04 03:20:25 +00:00
:value @(rf/subscribe [:time-color]) ;; subscribe
2016-10-20 20:07:38 +00:00
:on-change #(rf/dispatch [:time-color-change (-> % .-target .-value)])}]]) ;; < ---
2016-12-04 03:20:25 +00:00
```
2017-04-15 02:19:24 +00:00
Notice how it does BOTH a `subscribe` to obtain the current value AND
a `dispatch` to say when it has changed.
2016-12-04 03:20:25 +00:00
2017-04-15 02:19:24 +00:00
It is very common for view functions to run event-dispatching functions.
The user's interaction with the UI is usually the largest source of events.
2016-10-20 20:07:38 +00:00
2017-04-15 02:19:24 +00:00
And then a `view` function to bring the others together, which contains no
subscriptions or dispatching of its own:
2016-12-04 03:20:25 +00:00
```clj
2016-10-20 20:07:38 +00:00
(defn ui
[]
[:div
[:h1 "Hello world, it is now"]
[clock]
[color-input]])
```
2017-04-15 02:19:24 +00:00
Note: `view` functions tend to be organized into a hierarchy, often with
data flowing from parent to child via
parameters. So, not every view function needs a subscription. Very often
the values passed in from a parent component are sufficient.
2016-12-04 03:20:25 +00:00
2017-04-15 02:19:24 +00:00
Note: `view` functions should never directly access `app-db` . Data is
only ever sourced via subscriptions.
2016-10-24 03:21:47 +00:00
### Components Like Templates?
2016-12-04 03:20:25 +00:00
`view` functions are like the templates you'd find in
2016-12-04 23:49:04 +00:00
Django, Rails, Handlebars or Mustache -- they map data to HTML -- except for two massive differences:
2016-10-24 03:21:47 +00:00
1. you have the full power of ClojureScript available to you (generating a Clojure data structure). The
downside is that these are not "designer friendly" HTML templates.
2. these templates are reactive. When their input Signals change, they
are automatically rerun, producing new DOM. Reagent adroitly shields you from the details, but
2017-01-16 03:26:47 +00:00
the renderer of any `component` is wrapped by a `reaction` . If any of the "inputs"
to that renderer change, the renderer is rerun.
2016-10-24 03:21:47 +00:00
2016-10-20 20:07:38 +00:00
## Kick Starting The App
2017-07-31 22:09:28 +00:00
Below, `run` is called to kick off the application once the HTML page has loaded.
2016-10-20 20:07:38 +00:00
It has two tasks:
2017-01-16 03:26:47 +00:00
1. Load the initial application state
2017-04-15 02:19:24 +00:00
2. Load the GUI by "mounting" the root-level function in the hierarchy
of `view` functions -- in our case, `ui` --
2017-01-16 03:26:47 +00:00
onto an existing DOM element.
2016-10-20 20:07:38 +00:00
```clj
(defn ^:export run
[]
2016-12-07 22:56:18 +00:00
(rf/dispatch-sync [:initialize]) ;; puts a value into application state
2016-10-20 20:07:38 +00:00
(reagent/render [ui] ;; mount the application's ui into '< div id = "app" / > '
(js/document.getElementById "app")))
```
2017-01-16 03:26:47 +00:00
After `run` is called, the app passively waits for `events` .
2016-10-20 20:07:38 +00:00
Nothing happens without an `event` .
When it comes to establishing initial application state, you'll
2017-04-15 02:19:24 +00:00
notice the use of `dispatch-sync` , rather than `dispatch` . This is a simplifying cheat
which ensures that a correct
2016-12-04 03:20:25 +00:00
structure exists in `app-db` before any subscriptions or event handlers run.
2016-10-21 05:08:16 +00:00
## Summary
**Your job**, when building an app, is to:
- design your app's information model (data and schema layer)
2017-01-16 03:24:00 +00:00
- write and register event handler functions (control and transition layer) (domino 2)
2016-10-21 05:08:16 +00:00
- (once in a blue moon) write and register effect and coeffect handler
functions (domino 3) which do the mutative dirty work of which we dare not
speak in a pure, immutable functional context. Most of the time, you'll be
using standard, supplied ones.
- write and register query functions which implement nodes in a signal graph (query layer) (domino 4)
- write Reagent view functions (view layer) (domino 5)
2016-12-03 20:57:31 +00:00
2016-12-22 09:45:20 +00:00
## Next Steps
2016-12-04 03:20:25 +00:00
2017-04-15 02:19:24 +00:00
You should now take time to carefully review the
2017-09-12 04:37:28 +00:00
[todomvc example application ](https://github.com/Day8/re-frame/tree/master/examples/todomvc ).
2017-04-15 02:19:24 +00:00
On the one hand, it contains a lot of very helpful practical advice. On the other, it does
use some more advanced features like `interceptors` which are covered later in the docs.
2016-12-04 11:26:01 +00:00
2016-12-22 09:45:20 +00:00
After that, you'll be ready to write your own code. Perhaps you will use a
template to create your own project: < br >
Client only: https://github.com/Day8/re-frame-template < br >
Full Stack: http://www.luminusweb.net/
2017-04-15 02:19:24 +00:00
Obviously, you should also go on to read the further documentation.
2016-12-04 11:26:01 +00:00
***
Previous: [app-db (Application State) ](ApplicationState.md )
Up: [Index ](README.md )
2018-01-20 05:37:11 +00:00
Next: [Infographic: A re-frame Epoch ](AnEpoch.md )
2016-12-04 11:26:01 +00:00
2017-04-14 05:38:18 +00:00
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE - RUN doctoc TO UPDATE -->
<!-- END doctoc generated TOC please keep comment here to allow auto update -->