mirror of
https://github.com/status-im/re-frame.git
synced 2025-02-23 15:28:09 +00:00
Docs WIP - I think this is finally good enough for publish (git checkin 1001 for the repo, I think)
This commit is contained in:
parent
d8cad51db6
commit
fe87721c0e
98
README.md
98
README.md
@ -42,7 +42,7 @@ Perhaps:
|
||||
re-frame is a pattern for writing [SPAs] in ClojureScript, using [Reagent].
|
||||
|
||||
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?
|
||||
"McCoy, you trouble maker, why even mention an OO pattern?
|
||||
re-frame is a **functional framework**."
|
||||
|
||||
Being a functional framework, it is about data, and the pure functions
|
||||
@ -55,7 +55,7 @@ Architecturally, re-frame implements "a perpetual loop".
|
||||
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".
|
||||
provide - hence a tag line of "Derived Values, Flowing".
|
||||
|
||||
### It does Physics
|
||||
|
||||
@ -66,7 +66,7 @@ Remember this diagram from school? The water cycle, right?
|
||||
Two distinct stages, involving water in different phases, being acted upon
|
||||
by different forces: gravity working one way, evaporation/convection the other.
|
||||
|
||||
To understand re-frame, **imagine data flowing around that loop instead of water**.
|
||||
To understand re-frame, **imagine data flowing around that loop instead of water**.
|
||||
|
||||
re-frame
|
||||
provides the conveyance of the data around the loop - the equivalent of gravity, evaporation and convection.
|
||||
@ -87,13 +87,13 @@ you to understand re-frame, is **practically proof** it does physics.
|
||||
Computationally, each iteration of the loop involves a
|
||||
six domino cascade.
|
||||
|
||||
One domino triggers the next, which triggers the next, et cetera,
|
||||
until all the dominoes are knocked over. Then re-frame stands the dominoes up
|
||||
so the loop can repeat again. Each iteration is the same cascade, like a really boring OK Go video.
|
||||
One domino triggers the next, which triggers the next, et cetera, until we are
|
||||
back at the beginning of the loop, whereupoon the dominoes all spring to attention
|
||||
again, ready for the next iteration of the same cascade.
|
||||
|
||||
Here are the six dominoes ...
|
||||
|
||||
### 1st Domino - Event Initiation
|
||||
### 1st Domino - Event Dispatch
|
||||
|
||||
An `event` is sent when something happens - the user
|
||||
clicks a button, or a websocket receives a new message.
|
||||
@ -112,7 +112,7 @@ Event handler functions compute side effects (known in re-frame simply as `effec
|
||||
a **description of `effects`**. This description is a data structure
|
||||
which says, declaratively, how the world should change (because of the event).
|
||||
|
||||
Much of the time, only the "app state" of the SPA itself need
|
||||
Much of the time, only the "application state" of the SPA itself need
|
||||
change, but sometimes the outside world must also be effected
|
||||
(localstore, cookies, databases, emails, logs, etc).
|
||||
|
||||
@ -128,20 +128,19 @@ marvelous because they move the app forward. Without them, an app stays stuck in
|
||||
never achieving anything.
|
||||
|
||||
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, pluggable way.
|
||||
it does so in a largely hidden way, and in a manner which is debuggable, auditable, mockable and pluggable.
|
||||
|
||||
### A Pivot Point
|
||||
|
||||
The world has just changed and, very often,
|
||||
one particular part of the world, namely the **app's state**.
|
||||
The world just changed and, very often, one particular part of it: the **application state**.
|
||||
|
||||
re-frame's `app state` is held in one place - think of it like you
|
||||
would an in-memory, central database for the app (Much more details later).
|
||||
would an in-memory, central database for the app (more details later).
|
||||
|
||||
When domino 3 changes this `app state`, it triggers the next part of the cascade
|
||||
involving dominoes 4-5-6.
|
||||
|
||||
### The view formula
|
||||
### There's a formula for it
|
||||
|
||||
The 4-5-6 domino cascade implements the formula made famous by Facebook's ground-breaking React library:
|
||||
`v = f(s)`
|
||||
@ -164,7 +163,7 @@ 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
|
||||
be showing right now.
|
||||
|
||||
### Domino 4 - Query
|
||||
### Domino 4 - Query
|
||||
|
||||
Domino 4 is about extracting data from "app state", and providing it
|
||||
in the right format for view functions (which are Domino 5).
|
||||
@ -296,7 +295,7 @@ database.
|
||||
|
||||
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.
|
||||
itself computing the list of items.
|
||||
|
||||
Because the items
|
||||
are stored in app state, there's not a lot to compute in this case. This
|
||||
@ -307,7 +306,7 @@ subscription acts more like an accessor.
|
||||
(:items db)) ;; not much of a materialised view
|
||||
```
|
||||
|
||||
On program startup, such a query-fn must be associated with a key,
|
||||
On program startup, such a query-fn must be associated with an id,
|
||||
(for reasons obvious in the next domino) like this:
|
||||
```clj
|
||||
(re-frame.core/reg-sub :query-items query-fn)
|
||||
@ -329,8 +328,9 @@ for the deleted item, obviously, but otherwise the same DOM as last time).
|
||||
[:div (map item-render @items])) ;; assume item-render already written
|
||||
```
|
||||
|
||||
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.
|
||||
Notice how `items` is "sourced" from "app state" via `subscribe`. It is called with a query id
|
||||
to identify what data it needs - in Domino 4 we associated the query id `:query-items` with
|
||||
the function for that computation).
|
||||
|
||||
### Code For Domino 6
|
||||
|
||||
@ -348,9 +348,7 @@ The key point to understand about our 3-4-5-6 example is:
|
||||
- which triggers view functions to rerun
|
||||
- which causes new DOM
|
||||
|
||||
Boom, boom, boom go the dominoes.
|
||||
|
||||
It is a reactive data flow.
|
||||
Boom, boom, boom go the dominoes. It is a reactive data flow.
|
||||
|
||||
### Aaaaand we're done
|
||||
|
||||
@ -368,6 +366,56 @@ When building a re-frame app, you will:
|
||||
- write and register query functions which implement nodes in a signal graph (query layer) (domino 4)
|
||||
- write Reagent view functions (view layer) (domino 5)
|
||||
|
||||
|
||||
## Interconnections
|
||||
|
||||
Ask a Systems Theorist, and they'll tell you that a system has **parts** and **interconnections**.
|
||||
|
||||
Human brains tend to focus first on the **parts**, and then, later, maybe
|
||||
**interconnections**. But we know better, right? We
|
||||
know interconnections are often critical to a system.
|
||||
"Focus on the lines between the boxes" we lecture anyone kind enough to listen (in my case, glassy-eyed family members).
|
||||
|
||||
In the case of re-frame, dominoes are the **parts**, so, tick, yes, we have
|
||||
looked at them first. Our brains are happy. But what about the **interconnections**?
|
||||
|
||||
If the **parts** are functions, what does it even mean to talk about **interconnections between functions?**
|
||||
To answer that question, I'll rephrase it as:
|
||||
how are the domino functions **composed**?
|
||||
|
||||
At the language level,
|
||||
Uncle Alonzo and Uncle John tell us how a function like `count` composes:
|
||||
```clj
|
||||
(str (count (filter odd? [1 2 3 4 5])))
|
||||
```
|
||||
We know when `count` is called, and with what
|
||||
argument, and how the value it computes becomes the arg for a further function.
|
||||
We know how data "flows" into and out of the functions.
|
||||
|
||||
Sometimes, we'd rewrite this code as:
|
||||
```clj
|
||||
(->> [1 2 3 4 5]
|
||||
(filter odd?)
|
||||
count
|
||||
str)
|
||||
```
|
||||
With this arrangement, we talk of "threading" data
|
||||
through functions. **It seems to help our comprehension to frame function
|
||||
composition in terms of data flow**.
|
||||
|
||||
re-frame delivers architecture
|
||||
by supplying the interconnections - it threads the data - it composes the dominoes - it is the lines between the boxes.
|
||||
|
||||
But re-frame has no universal method for this. The technique it uses varies from one domino neighbour
|
||||
pair to the next. Between 1 and 2 it is a queue & router,
|
||||
between 2 and 3 it is an interceptor pipeline, and along the 3-4-5-6 domino axis there's a reactive signal graph. The right
|
||||
tool for the job in each case, I'd argue.
|
||||
|
||||
While interconnections are critical to how **re-frame works**,
|
||||
you can happily **use re-frame** for a long time and be mostly ignorant of their details.
|
||||
|
||||
Which is a good thing - back we go to happy brains focusing on the **parts**.
|
||||
|
||||
## It Leverages Data
|
||||
|
||||
You might already know that ClojureScript is a modern lisp, and that
|
||||
@ -431,16 +479,16 @@ and useful 3rd party libraries.
|
||||
|
||||
We haven't looked at much code yet, 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.
|
||||
but the core concepts, and even basic coding techniques, are now known to you.
|
||||
|
||||
Next you need to read read the other three articles in the documentation [Introduction section](/docs#introduction):
|
||||
Next you need to read read the other three articles in the [Introduction section](/docs#introduction):
|
||||
|
||||
* [Application State](/docs/ApplicationState.md)
|
||||
* [Code Walkthrough](/docs/CodeWalkthrough.md)
|
||||
* [Mental Model Omnibus](/docs/MentalModelOmnibus.md)
|
||||
|
||||
This will get your knowledge to about 70%. The
|
||||
final 30% will come incrementally with use, and by reading the
|
||||
final 30% will come incrementally with use, and by reading the other
|
||||
tutorials (of which there's a few).
|
||||
|
||||
You can also experiment with these examples: <br>
|
||||
@ -457,7 +505,7 @@ https://github.com/Day8/re-frame/blob/develop/docs/External-Resources.md
|
||||
|
||||
Good news. If you've read this far,
|
||||
your insiders T-shirt will be arriving soon - it will feature turtles,
|
||||
[xkcd](http://xkcd.com/1416/) and something indicating "data all the way down".
|
||||
[xkcd](http://xkcd.com/1416/) and something about "data all the way down".
|
||||
But we're still working on the hilarious caption bit. Open a
|
||||
repo issue with a suggestion.
|
||||
|
||||
|
@ -100,6 +100,17 @@ source of data is elsewhere.
|
||||
6. The ability to do time travel debugging, even in a production setting. More soon.
|
||||
|
||||
|
||||
### Get You A Leveragable Schema
|
||||
|
||||
You, really do need a schema for `app-db`. Yes, it is optional, and I breezed past this
|
||||
earlier, but now I'm thumping the table and my face is red with intensity. You need one.
|
||||
|
||||
The todomvc example (in this repo) shows how to check `app-db` against your schema
|
||||
after every single event has been processed.
|
||||
|
||||
This is good: <br>
|
||||
https://www.youtube.com/watch?v=VNTQ-M_uSo8
|
||||
|
||||
***
|
||||
|
||||
Previous: [This Repo's README](../README.md)
|
||||
|
@ -461,9 +461,9 @@ structure exists in `app-db` before any subscriptions or event handlers run.
|
||||
- write and register query functions which implement nodes in a signal graph (query layer) (domino 4)
|
||||
- write Reagent view functions (view layer) (domino 5)
|
||||
|
||||
## Further
|
||||
## Further Code
|
||||
|
||||
You should look at the [todomvc example application](https://github.com/Day8/re-frame/tree/develop/examples/todomvc).
|
||||
You should also look at the [todomvc example application](https://github.com/Day8/re-frame/tree/develop/examples/todomvc).
|
||||
|
||||
|
||||
***
|
||||
|
@ -18,7 +18,7 @@ and help you to get the best from it.
|
||||
|
||||
This tutorial is a tour
|
||||
of these ideas, justifications and insights. It is a little rambling, but
|
||||
I'm hoping you'll have had at least one "Oooh, I see" moment before the end.
|
||||
I'm hoping you'll have had at least one "Aaaah, I see" moment before the end.
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
@ -220,7 +220,7 @@ contrived in other kinds of architecture (in my experience).
|
||||
|
||||
So, members of the jury, I put it to you that:
|
||||
- the first 3 dominoes implement an [Event-driven finite-state machine](https://en.wikipedia.org/wiki/Event-driven_finite-state_machine)
|
||||
- the last 3 dominoes a rendering of the FSM's current state for the user to observe
|
||||
- the last 3 dominoes render of the FSM's current state for the user to observe
|
||||
|
||||
Depending on your app, this may or may not be a useful mental model,
|
||||
but one thing is for sure ...
|
||||
@ -259,3 +259,17 @@ Your love for re-frame will be deep, abiding and enriching.
|
||||
Previous: [First Code Walk-Through](CodeWalkthrough.md)
|
||||
Up: [Index](README.md)
|
||||
Next: [Effectful Handlers](EffectfulHandlers.md)
|
||||
|
||||
|
||||
[SPAs]:http://en.wikipedia.org/wiki/Single-page_application
|
||||
[SPA]:http://en.wikipedia.org/wiki/Single-page_application
|
||||
[Reagent]:http://reagent-project.github.io/
|
||||
[Dan Holmsand]:https://twitter.com/holmsand
|
||||
[Flux]:http://facebook.github.io/flux/docs/overview.html#content
|
||||
[Hiccup]:https://github.com/weavejester/hiccup
|
||||
[FRP]:https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
|
||||
[Elm]:http://elm-lang.org/
|
||||
[OM]:https://github.com/swannodette/om
|
||||
[Prismatic Schema]:https://github.com/Prismatic/schema
|
||||
[Hoplon]:http://hoplon.io/
|
||||
[Pedestal App]:https://github.com/pedestal/pedestal-app
|
||||
|
@ -5,65 +5,7 @@ We'll look at the underlying reactive mechanism.
|
||||
|
||||
BUT we'll start by looking at the overall picture ...
|
||||
|
||||
## Interconnections
|
||||
|
||||
Ask a Systems Theorist, and they'll tell you that a system has **parts** and **interconnections**.
|
||||
|
||||
Human brains tend to focus first on **parts**, and then, later,
|
||||
**interconnections**. But we Software Architect might focus on
|
||||
the interconnections earlier because they're so often critical to an understanding of the system.
|
||||
"Focus on the lines between the boxes" we might lecture anyone kind enough to listen.
|
||||
|
||||
In the case of re-frame, dominoes are the **parts**, so, tick, yes, we have
|
||||
looked at them first. So, I hope your brain is happy. But, let's now
|
||||
indulge our inner Systems Architect and think more about **interconnections**.
|
||||
|
||||
So, if the **parts** are functions, what then are
|
||||
the **interconnections**?
|
||||
|
||||
What does it even mean to talk about **interconnections between functions?**
|
||||
To answer that question, I'll rephrase it as:
|
||||
how are the domino functions **composed**?
|
||||
|
||||
At the language level,
|
||||
Uncle Alonzo and Uncle John say a function such as `count` composes like this:
|
||||
```clj
|
||||
(str (count (filter odd? [1 2 3 4 5])))
|
||||
```
|
||||
Clojure's semantics tell us when `count` is called, and with what
|
||||
argument, and how the value it computes becomes the arg for a further function.
|
||||
We know how data "flows" into and out of the functions.
|
||||
|
||||
Sometimes, we'd rewrite the code above as:
|
||||
```clj
|
||||
(->> [1 2 3 4 5]
|
||||
(filter odd?)
|
||||
count
|
||||
str)
|
||||
```
|
||||
When we arrange our code like this, we talk of "threading" data
|
||||
through functions. **It seems to help our comprehension to frame function
|
||||
composition in terms of data flow**.
|
||||
|
||||
re-frame delivers architecture
|
||||
by supplying the interconnections - it threads the data - it lives in the gaps.
|
||||
|
||||
But there's no one method of threading. The flow varies from one domino neighbour pair to the next. One time it is a queue,
|
||||
another a pipeline, and along the 3-4-5-6 axis there's a reactive signal graph.
|
||||
|
||||
Fine. So how, then, does data get threaded through the domino functions of re-frame?
|
||||
How does data flow out of one function (domino)
|
||||
into the next? What theory of computation is driving this bus?
|
||||
|
||||
My first, weak answer is: how wonderful is it that you don't need to worry about
|
||||
this too much, re-frame looks
|
||||
after it for you. It will thread (convey) data from one domino function to the next.
|
||||
It will call your functions at the right time, with the right (data) arguments.
|
||||
|
||||
My second, equally unsatisfactory answer is: the method/transport varies
|
||||
from one domino pair to the next. There's no one method. You'll need to read the further docs on "Flow".
|
||||
|
||||
At this point, my goal was to start you thinking about "the lines between the boxes". That's where re-frame lives.
|
||||
|
||||
## 1 -> 2
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user