re-frame/README.md

468 lines
18 KiB
Markdown
Raw Normal View History

2016-12-04 11:26:01 +00:00
[logo](/images/logo/re-frame_128w.png?raw=true)
2015-03-04 04:41:22 +00:00
2016-07-15 13:52:42 +00:00
## Derived Values, Flowing
2014-12-12 14:20:41 +00:00
2015-02-10 13:31:41 +00:00
> This, milord, is my family's axe. We have owned it for almost nine hundred years, see. Of course,
sometimes it needed a new blade. And sometimes it has required a new handle, new designs on the
2016-12-04 11:26:01 +00:00
metalwork, a little refreshing of the ornamentation ... but is this not the nine hundred-year-old
2015-02-10 13:31:41 +00:00
axe of my family? And because it has changed gently over time, it is still a pretty good axe,
y'know. Pretty good.
2016-12-04 11:26:01 +00:00
> -- Terry Pratchett, The Fifth Elephant <br>
> &nbsp;&nbsp;&nbsp; Reflecting on identity, flow and derived values
2015-05-02 15:41:16 +00:00
[![Clojars Project](https://img.shields.io/clojars/v/re-frame.svg)](https://clojars.org/re-frame)
[![GitHub license](https://img.shields.io/github/license/Day8/re-frame.svg)](license.txt)
[![Circle CI](https://circleci.com/gh/Day8/re-frame/tree/develop.svg?style=shield&circle-token=:circle-ci-badge-token)](https://circleci.com/gh/Day8/re-frame/tree/develop)
[![Circle CI](https://circleci.com/gh/Day8/re-frame/tree/master.svg?style=shield&circle-token=:circle-ci-badge-token)](https://circleci.com/gh/Day8/re-frame/tree/master)
2014-12-08 21:46:34 +00:00
2015-01-11 21:51:55 +00:00
2016-12-04 11:26:01 +00:00
## Why Should You Care?
2014-12-10 10:48:27 +00:00
2016-12-04 11:26:01 +00:00
Perhaps:
2016-09-05 15:48:31 +00:00
2016-12-04 11:26:01 +00:00
1. You want to develop an [SPA] in ClojureScript, and you are looking for a framework
2. You believe Facebook did something magnificent when it created React, and
you are curious about the further implications. Is the combination of
`reactive programming`, `functional programming` and `immutable data` going to
**completely change everything**? And, if so, what would that look like in a language
that embraces those paradigms?
3. You're taking a [Functional Design and Programming course at San Diego State University](http://www.eli.sdsu.edu/courses/fall15/cs696/index.html)
and you have a re-frame/reagent assignment due. You've left the reading a bit late, right? I remember those days. Just.
4. re-frame is impressively buzzword compliant: it has reactivity,
unidirectional data flow, pristinely pure functions,
interceptors, coeffects, conveyor belts, statechart-friendliness (FSM)
and claims an immaculate hammock conception. It also has a charming
xkcd reference (soon) and a hilarious, insiders-joke T-shirt,
ideal for conferences (in design). What could possibly go wrong?
2014-12-08 21:46:34 +00:00
2016-12-04 11:26:01 +00:00
## re-frame
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
re-frame is a pattern for writing [SPAs] in ClojureScript, using [Reagent].
2014-12-16 22:29:12 +00:00
2016-12-04 11:26:01 +00:00
McCoy might report "It's MVC, Jim, but not as we know it". And you would respond
"McCoy, you damn trouble maker, why even mention an OO pattern?
re-frame is a **functional framework**."
2016-09-05 15:48:31 +00:00
2016-12-04 11:26:01 +00:00
Being a functional framework, it is about data, and the pure functions
which transform that data.
2015-01-20 22:40:49 +00:00
2016-12-04 11:26:01 +00:00
### It is a loop
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
Architecturally, re-frame implements "a perpetual loop".
2015-02-05 12:46:54 +00:00
2016-12-04 11:26:01 +00:00
To build an app, you hang pure functions on certain parts of this loop,
and re-frame looks after the `conveyance of data`
around the loop, into and out of the transforming functions you
provide - which is why the tag line is "Derived Values, Flowing".
2015-01-25 23:42:45 +00:00
2016-12-04 11:26:01 +00:00
### It does Physics
2015-01-25 23:42:45 +00:00
2016-12-04 11:26:01 +00:00
Remember this diagram from school? The water cycle, right?
2015-01-11 12:09:17 +00:00
2016-12-04 11:26:01 +00:00
<img height="350px" align="right" src="/images/the-water-cycle.png?raw=true">
2015-01-14 05:19:37 +00:00
2016-12-04 11:26:01 +00:00
Two distinct stages, involving water in different phases, being acted upon
by different forces: gravity working one way, evaporation/convection the other.
2015-01-14 05:19:37 +00:00
2016-12-04 11:26:01 +00:00
To understand re-frame, **imagine data flowing around that loop instead of water**.
2015-01-14 12:01:29 +00:00
2016-12-04 11:26:01 +00:00
re-frame
provides the conveyance of the data around the loop - the equivalent of gravity, evaporation and convection.
You design what's flowing and then you hang functions off the loop at
various points to compute the data's phase changes.
2015-02-04 11:35:11 +00:00
2016-12-04 11:26:01 +00:00
Sure, right now, you're thinking "lazy sod - make a proper Computer Science-y diagram". But, no.
Joe Armstrong says "don't break the laws of physics" - I'm sure
you've seen the videos - and if he says to do something, you do it
(unless Rich Hickey disagrees, and says to do something else). So,
this diagram, apart from being a plausible analogy which might help
you to understand re-frame, is **practically proof** it does physics.
2015-01-25 23:42:45 +00:00
2016-12-04 11:26:01 +00:00
### It is a 6-domino cascade
2014-12-09 18:03:11 +00:00
2016-12-04 11:26:01 +00:00
<img align="right" src="/images/Readme/Dominoes-small.jpg?raw=true">
2014-12-16 22:29:12 +00:00
2016-12-04 11:26:01 +00:00
Computationally, each iteration of the loop involves a
6 domino cascade.
2014-12-16 22:29:12 +00:00
2016-12-04 11:26:01 +00:00
One domino triggers the next, which triggers the next, etc,
until we are back at the beginning of the loop. Each iteration is the same cascade.
2014-12-11 20:20:55 +00:00
2016-12-04 11:26:01 +00:00
Here are the 6 dominoes ...
2014-12-11 20:20:55 +00:00
2016-12-04 20:34:20 +00:00
### 1st Domino - Event Initiation
2014-12-11 20:20:55 +00:00
2016-12-04 11:26:01 +00:00
An `event` is sent when something happens - the user
clicks a button, or a websocket receives a new message.
2015-01-11 12:09:17 +00:00
2016-12-04 11:26:01 +00:00
Without the impulse of a triggering `event`, no 6 domino cascade occurs.
It is only because of `events` that a re-frame app is propelled,
loop iteration after loop iteration, from one state to the next.
2015-01-11 12:09:17 +00:00
2016-12-04 11:26:01 +00:00
re-frame is `event` driven.
2015-01-11 12:09:17 +00:00
2016-12-04 20:34:20 +00:00
### 2nd Domino - Event Handling
2015-01-14 12:01:29 +00:00
2016-12-04 11:26:01 +00:00
In response to an `event`, an application must compute
its implication (the ambition, the intent). This is known as `event handling`.
2014-12-12 11:50:39 +00:00
2016-12-04 11:26:01 +00:00
Event handler functions compute `effects` or, more accurately,
a **description of `effects`**. So they compute a data structure
which says, declaratively, how the world should change (because of the event).
2014-12-17 01:45:35 +00:00
2016-12-04 11:26:01 +00:00
Much of the time, only the "app state" of the SPA itself need
change, but sometimes the outside world must also be effected
(localstore, cookies, databases, emails, logs, etc).
2014-12-09 18:03:11 +00:00
2016-12-04 20:34:20 +00:00
### 3rd Domino - Effect Handling
2016-12-04 20:34:20 +00:00
These descriptions of `effects` are realised (actioned).
2014-12-10 10:48:27 +00:00
2016-12-04 11:26:01 +00:00
Now, to a functional programmer, `effects` are scary in a
[xenomorph kind of way](https://www.google.com.au/search?q=xenomorph).
Nothing messes with functional purity
quite like the need for effects and coeffects. But, on the other hand, `effects` are equally
marvelous because they take the app forward. Without them, an app stays stuck in one state forever,
never achieving anything.
2014-12-12 11:50:39 +00:00
2016-12-04 11:26:01 +00:00
So re-frame embraces the protagonist nature of `effects` - the entire, unruly zoo of them - but
it does so in a controlled, debuggable, auditable, mockable, plugable way.
2014-12-09 18:03:11 +00:00
2016-12-04 20:34:20 +00:00
### A Pivot Point
2014-12-11 20:20:55 +00:00
2016-12-04 20:34:20 +00:00
The world has just changed and, very often,
2016-12-04 11:26:01 +00:00
one particular part of the world, namely the **app's state**.
2014-12-11 20:20:55 +00:00
2016-12-04 11:26:01 +00:00
re-frame's `app state` is held in one place - think of it like you
2016-12-04 20:34:20 +00:00
would an in-memory, central database for the app. (Much more details later)
2014-12-09 18:03:11 +00:00
2016-12-04 11:26:01 +00:00
When domino 3 changes this `app state`, it triggers the next part of the cascade
involving dominoes 4-5-6.
2014-12-11 20:20:55 +00:00
2016-12-04 11:26:01 +00:00
### The view formula
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
The 4-5-6 domino cascade implements the formula made famous by Facebook's ground-breaking React library:
`v = f(s)`
2014-12-12 11:50:39 +00:00
2016-12-04 23:49:04 +00:00
A view, `v`, is a function, `f`, of the app state, `s`.
2014-12-08 21:46:34 +00:00
2016-12-04 23:49:04 +00:00
Or, said another way, there are functions `f` that compute which DOM nodes, `v`,
2016-12-04 11:26:01 +00:00
should be displayed to the user when the application is in a given app state, `s`.
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
Or, another way: **over time**, as `s` changes, `f`
will be re-run each time to compute new `v`, forever keeping `v` up to date with the current `s`.
2014-12-17 05:23:22 +00:00
2016-12-04 20:34:20 +00:00
In our case, domino 3 changes `s`, the application state,
and, in response, dominoes 4-5-6 are concerned with re-running `f` to compute the new `v`
2016-12-04 11:26:01 +00:00
shown to the user.
2014-12-08 21:46:34 +00:00
2016-12-04 23:49:04 +00:00
Except, of course, there are nuances. For instance, there's no single `f` to run.
2016-12-04 11:26:01 +00:00
There may be many functions which collectively build the overall DOM,
and only part of `s` may change at any one time, so only part of the
`v` (DOM) need be re-computed and updated. And some parts of `v` might not
even be showing right now.
2014-12-17 05:23:22 +00:00
2016-12-04 20:34:20 +00:00
### Domino 4 - Query
2014-12-17 05:23:22 +00:00
2016-12-04 23:49:04 +00:00
Domino 4 is about extracting data from "app state", and providing it
in the right format for view functions (which are Domino 5).
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
Domino 4 is a novel and efficient de-duplicated signal graph which
runs query functions on the app state, `s`, efficiently computing
reactive, multi-layered, "materialised views" of `s`.
2014-12-11 20:20:55 +00:00
2016-12-04 11:26:01 +00:00
(Relax about any unfamiliar terminology, you'll soon
see how simple the code actually is)
2014-12-11 20:20:55 +00:00
2016-12-04 20:34:20 +00:00
### Domino 5 - View
2014-12-17 05:23:22 +00:00
2016-12-04 23:49:04 +00:00
Domino 5 is one or more **view functions** (aka Reagent components) that compute the
UI DOM that should be displayed to the user.
2014-12-16 22:29:12 +00:00
2016-12-04 20:34:20 +00:00
To render the right UI, they need to source application state, which is
2016-12-04 23:49:04 +00:00
delivered reactively via the queries of Domino 4. They
2016-12-04 20:34:20 +00:00
compute hiccup-formatted data, which is a description of the DOM required.
2014-12-11 20:20:55 +00:00
2016-12-04 20:34:20 +00:00
### Domino 6 - DOM
2014-12-11 20:20:55 +00:00
2016-12-04 20:34:20 +00:00
You don't write Domino 6 - it is handled for you
2016-12-04 23:49:04 +00:00
by Reagent/React. I mention it here
2016-12-04 11:26:01 +00:00
for completeness and to fully close the loop.
2014-12-12 12:37:29 +00:00
2016-12-04 11:26:01 +00:00
This is the step in which the hiccup-formatted
2016-12-04 20:34:20 +00:00
"descriptions of required DOM", returned by the view functions of Domino 5, are made real. The
2016-12-04 11:26:01 +00:00
browser DOM nodes are mutated.
2014-12-16 22:29:12 +00:00
2016-12-04 11:26:01 +00:00
## A Cascade Of Simple Functions
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
**Each of the dominoes you write are simple, pure functions** which
can be be described, understood and
tested independently. They take data, transform it and return new data.
2014-12-11 20:20:55 +00:00
2016-12-04 11:26:01 +00:00
The loop itself is very mechanical in operation.
So, there's a regularity, simplicity and
certainty to how a re-frame app goes about its business,
2016-12-04 20:34:20 +00:00
which leads, in turn, to an ease in reasoning and debugging. This is
key to why re-frame is so pleasing to work with - it is just so
straightforward.
2014-12-15 06:48:20 +00:00
2016-12-04 11:26:01 +00:00
## Managing mutation
2015-02-05 12:46:54 +00:00
2016-12-04 11:26:01 +00:00
The two sub-cascades 1-2-3 and 4-5-6 have a similar structure.
2015-02-05 12:46:54 +00:00
2016-12-04 23:49:04 +00:00
In each, it is the second to last domino which
2016-12-04 11:26:01 +00:00
computes "descriptions" of mutations required, and it is
the last domino which does the dirty work and realises these descriptions.
2014-12-12 11:50:39 +00:00
2016-12-04 23:49:04 +00:00
In both cases, you don't need to worry yourself about this dirty work. re-frame looks
2016-12-04 11:26:01 +00:00
after those dominoes.
2014-12-08 21:46:34 +00:00
2016-12-04 11:26:01 +00:00
## Code Fragments
2014-12-16 22:29:12 +00:00
2016-12-04 20:34:20 +00:00
Let's take this domino narrative one step further and introduce some code fragments.
2014-12-12 11:50:39 +00:00
2016-12-04 20:34:20 +00:00
> Don't expect
to completely grok the terse code presented below. We're still at 30,000 feet. Details later.
2016-12-04 11:26:01 +00:00
**Imagine:** the UI of an SPA shows a list of items. This user
clicks the "delete" button next to the 3rd item in a list.
2014-12-11 01:48:41 +00:00
2016-12-04 11:26:01 +00:00
In response,
what happens within this imaginary re-frame app? Here's a sketch of the 6 domino cascade:
2014-12-17 14:42:16 +00:00
2016-12-04 11:26:01 +00:00
### Code For Domino 1
2014-12-11 01:48:41 +00:00
2016-12-04 11:26:01 +00:00
The delete button for that 3rd item will have an `on-click` handler (function) which looks
like this:
```clj
#(re-frame.core/dispatch [:delete-item 2486])
2014-12-11 01:48:41 +00:00
```
2016-12-04 20:34:20 +00:00
`dispatch` emits an `event`.
2016-12-04 23:49:04 +00:00
A re-frame `event` is a vector and, in this case,
2016-12-04 11:26:01 +00:00
it has 2 elements: `[:delete-item 2486]`. The first element,
2016-12-04 23:49:04 +00:00
`:delete-item`, is the kind of event. The rest is optional, further data about the
2016-12-04 11:26:01 +00:00
`event` - in this case, my made-up id, `2486`, for the item to delete.
2014-12-11 01:48:41 +00:00
2016-12-04 11:26:01 +00:00
### Code For Domino 2
2014-12-11 01:48:41 +00:00
2016-12-04 11:26:01 +00:00
The `event handler`, `h`, associated with
`:delete-item` is called to compute the `effect` of this event.
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
This handler function, `h`, must take two arguments: the state-of-the-world
and the event, and it must return an effects map. Without going into any
explanations at this early point, here's a sketch of what a handler
might look like:
```clj
(defn h
[{:keys [db]} event] ;; args: db from coeffect, event
(let [item-id (second event)] ;; extract id from event vector
{:db (dissoc-in db [:items item-id])})) ;; effect is change db
2014-12-11 01:48:41 +00:00
```
2014-12-11 07:11:01 +00:00
2016-12-04 20:34:20 +00:00
On program startup, `h` would have been
associated with `:delete-item` `events` like this:
2016-12-04 11:26:01 +00:00
```clj
(re-frame.core/reg-event-fx :delete-item h)
2014-12-12 13:19:14 +00:00
```
2016-12-04 11:26:01 +00:00
### Code For Domino 3
2014-12-12 13:19:14 +00:00
2016-12-04 20:34:20 +00:00
An `effect handler` (function) actions the `effects` returned by `h`:
2016-12-04 11:26:01 +00:00
```clj
{:db (dissoc-in db [:items item-id])}
2014-12-15 06:48:20 +00:00
```
2016-12-04 20:34:20 +00:00
So that's a map. The keys identify the required kind of `effect`, and the values
2016-12-04 23:49:04 +00:00
supply further details.
2014-12-15 06:48:20 +00:00
2016-12-04 11:26:01 +00:00
A key of `:db` means to update the app state, with the new computed value.
2014-12-15 06:48:20 +00:00
2016-12-04 23:49:04 +00:00
This update of "app state" is a mutative step, facilitated by re-frame
2016-12-04 11:26:01 +00:00
when it sees a `:db` effect.
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
Why the name `:db`? re-frame sees "app state" as something of an in-memory
database.
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
### Code For Domino 4
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
Because a new version of "app state" has been computed and installed,
a query (function) over this app state is called automatically (reactively),
itself computing the list of items.
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
Because the items
are stored in app state, there's not a lot to compute in this case. This
subscription acts more like an accessor.
```clj
(defn query-fn
[db _] ;; db is current app state
(:items db)) ;; not much of a materialised view
2014-12-16 22:29:12 +00:00
```
2014-12-15 06:48:20 +00:00
2016-12-04 23:49:04 +00:00
On program startup, such a query-fn must be associated with a key,
2016-12-04 11:26:01 +00:00
(for reasons obvious in the next domino) like this:
```clj
(re-frame.core/reg-sub :query-items query-fn)
2014-12-15 11:56:43 +00:00
```
2016-12-04 11:26:01 +00:00
### Code For Domino 5
2014-12-15 06:48:20 +00:00
2016-12-04 11:26:01 +00:00
Because the query function re-computed a new value, a view (function) which subscribes
2016-12-04 20:34:20 +00:00
to "items", is called automatically (reactively) to re-compute DOM.
It produces
2016-12-04 11:26:01 +00:00
a hiccup-formatted data structure describing the DOM nodes required (no DOM nodes
for the deleted item, obviously, but otherwise the same DOM as last time).
2016-12-04 23:49:04 +00:00
2016-12-04 11:26:01 +00:00
```clj
(defn items-view
2015-02-20 13:45:48 +00:00
[]
2016-12-04 11:26:01 +00:00
(let [items (subscribe [:query-items])] ;; source items from app state
2016-12-04 23:49:04 +00:00
[:div (map item-render @items])) ;; assume item-render already written
2014-12-16 22:29:12 +00:00
```
2014-12-15 13:29:33 +00:00
2016-12-04 20:34:20 +00:00
Notice how `items` is "sourced" from "app state" via `subscribe`. It is called with a query key
to identify what data it needs, which should make a prior registration.
2016-12-04 11:26:01 +00:00
### Code For Domino 6
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
The computed DOM (hiccup) is made real by Reagent/React. No code from you required. Just happens.
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
The DOM "this
time" is the same as last time, except for the absence of DOM for the
2016-12-04 20:34:20 +00:00
deleted item, so the mutation will be to remove some DOM nodes.
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
### 3-4-5-6 Summary
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
The key point to understand about our 3-4-5-6 example is:
- a change to app state ...
- triggers query functions to rerun ...
- which triggers view functions to rerun
- which causes new DOM
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
Boom, boom, boom go the dominoes.
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
It is a reactive data flow.
2015-01-20 22:40:49 +00:00
2016-12-04 11:26:01 +00:00
### Aaaaand we're done
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
At this point, the re-frame app returns to a quiescent state,
waiting for the next event.
2014-12-15 13:29:33 +00:00
2016-12-04 11:26:01 +00:00
## So, your job is ...
2015-01-20 22:40:49 +00:00
2016-12-04 11:26:01 +00:00
When building a re-frame app, you will:
- design your app's information model (data and schema layer)
- write and register event handler functions (control and transition layer) (domino 2)
- (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.
- write and register query functions which implement nodes in a signal graph (query layer) (domino 4)
- write Reagent view functions (view layer) (domino 5)
2015-01-20 22:40:49 +00:00
2016-12-04 11:26:01 +00:00
## It Leverages Data
2014-12-17 05:23:22 +00:00
2016-12-04 11:26:01 +00:00
You might already know that ClojureScript is a modern lisp, and that
lisps are **homoiconic**. If not, you do now.
2015-01-20 22:40:49 +00:00
2016-12-04 11:26:01 +00:00
The homoiconic bit is significant. It means you program in a lisp by creating and
assembling lisp data structures. Think about that. You are **programming in data**.
The functions which later manipulate data, start as data.
2015-02-20 13:45:48 +00:00
2016-12-04 11:26:01 +00:00
Clojure programmers place particular
emphasis on the primacy of data. When they aren't re-watching Rich Hickey videos,
and wishing their hair was darker and more curly,
they meditate on aphorisms like "Data is the ultimate in late binding".
2015-01-20 22:40:49 +00:00
2016-12-04 23:49:04 +00:00
I cannot stress enough what a big deal this is. It can seem
2016-12-04 11:26:01 +00:00
like a syntax curiosity at first but, when the penny drops for
you on this, it tends to be a profound moment. And once you
understand the importance of this concept at the language level,
you naturally want to leverage similar power at the library level.
2014-12-15 13:29:33 +00:00
2016-12-04 11:26:01 +00:00
So, it will come as no surprise, then, to know that re-frame has a
data oriented design. Events are data. Effects are data. DOM is data.
The functions which transform data are registered and looked up via
data. Interceptors (data) are preferred over middleware (higher
order functions). Etc.
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
Data - that's the way we roll.
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
## It is mature and proven in the large
2015-02-10 13:31:41 +00:00
2016-12-04 11:26:01 +00:00
re-frame was released in early 2015, and has since [been](https://www.fullcontact.com)
successfully
[used](https://www.nubank.com.br)
by
[quite](http://open.mediaexpress.reuters.com/)
a
[few](https://rokt.com/) companies and
individuals to build complex apps, many running beyond 40K lines of
ClojureScript.
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
<img align="right" src="/images/scale-changes-everything.jpg?raw=true">
2015-01-11 12:09:17 +00:00
2016-12-04 11:26:01 +00:00
**Scale changes everything.** Frameworks
are just pesky overhead at small scale - measure them instead by how they help
you tame the complexity of bigger apps, and in this regard re-frame has
worked out well. Some have been effusive in their praise.
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
Having said that, re-frame remains a work in progress and it falls
short in a couple of ways - for example it doesn't work as well as we'd
like with devcards, because it is a framework, rather than a library.
We're still puzzling over some aspects and tweaking as we go. All designs
represent a point in the possible design space, with pros and cons.
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
And, yes, re-frame is fast, straight out of the box. And, yes, it has
a good testing story (unit and behavioural). And, yes, it works in with figwheel to create
a delightful hot-loading development story. And, yes, it has
2016-12-04 23:49:04 +00:00
fun specialist tooling, and a community,
2016-12-04 11:26:01 +00:00
and useful 3rd party libraries.
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
## Where Do I Go Next?
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
We haven't yet looked at code much, but **at this point you
already know 50% of re-frame.** There's detail to fill in, for sure,
but the core concepts, and basic coding techniques, are now known to you.
2014-12-10 15:33:57 +00:00
2016-12-04 11:26:01 +00:00
Next, you need to do the code walk-through in the tutorial. This
will get your knowledge to about 70%. The
2016-12-04 23:49:04 +00:00
final 30% will come incrementally with use, and by reading the
2016-12-04 11:26:01 +00:00
tutorials (of which there's a few).
2014-12-11 01:48:41 +00:00
2016-12-04 11:26:01 +00:00
So, next, read more here: <br>
https://github.com/Day8/re-frame/blob/master/docs/README.md
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
Experiment with these examples: <br>
https://github.com/Day8/re-frame/tree/master/examples
2016-12-04 11:26:01 +00:00
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/
2016-12-04 11:26:01 +00:00
Use these resources: <br>
https://github.com/Day8/re-frame/blob/develop/docs/External-Resources.md
2014-12-17 01:23:53 +00:00
2016-12-04 11:26:01 +00:00
### T-Shirt Unlocked
2015-02-18 08:43:13 +00:00
Good news. If you've read this far,
your insiders T-shirt will be arriving soon - it
2016-12-04 11:26:01 +00:00
will feature turtles,
[xkcd](http://xkcd.com/1416/) and something indicating "data all the way down".
But we're still working on the hilarious caption bit. Open a
2015-02-20 05:46:50 +00:00
repo issue with a suggestion.
2015-02-11 01:22:49 +00:00
2016-12-04 11:26:01 +00:00
## Licence
2015-02-04 11:35:11 +00:00
2016-12-04 11:26:01 +00:00
Copyright © 2014-2016 Michael Thompson
2015-02-25 21:26:08 +00:00
Distributed under The MIT License (MIT) - See LICENSE.txt
2016-12-04 11:26:01 +00:00
2014-12-09 18:03:11 +00:00
[SPAs]:http://en.wikipedia.org/wiki/Single-page_application
2015-03-07 10:35:32 +00:00
[SPA]:http://en.wikipedia.org/wiki/Single-page_application
2014-12-17 14:42:16 +00:00
[Reagent]:http://reagent-project.github.io/