More docs review
This commit is contained in:
parent
3f0679f396
commit
fead1b04b3
|
@ -5,9 +5,6 @@ Yes, a surprising claim.
|
|||
|
||||
## Table Of Contents
|
||||
|
||||
- [Effectful Handlers](#effectful-handlers)
|
||||
- [Table Of Contents](#table-of-contents)
|
||||
- [Effects](#effects)
|
||||
* [Events Happen](#events-happen)
|
||||
* [Handling The Happening](#handling-the-happening)
|
||||
* [Your Handling](#your-handling)
|
||||
|
@ -41,16 +38,16 @@ message arrives on a websocket.
|
|||
|
||||
### Handling The Happening
|
||||
|
||||
Once dispatched, an event must be "handled". It must be processed, actioned.
|
||||
Once dispatched, an event must be "handled" - which means it must be processed or actioned.
|
||||
|
||||
Events are mutative by nature. If your application is in one state before an
|
||||
event is processed, it will be in a different state afterwards.
|
||||
|
||||
And that state change is very desirable. Without the state change our
|
||||
application can't incorporate that button click, or the newly arrived
|
||||
websocket message. Without mutation, the apps just sits there, stuck.
|
||||
websocket message. Without mutation, an app would just sits there, stuck.
|
||||
|
||||
State change is how the application "moves forward" - how it does its job. Useful!
|
||||
State change is how an application "moves forward" - how it does its job. Useful!
|
||||
|
||||
On the other hand, control logic and state mutation tend to be the most
|
||||
complex and error prone of part of an app.
|
||||
|
@ -63,7 +60,7 @@ provided you with a simple programming model.
|
|||
It said you should call `reg-event-db` to associate an event id,
|
||||
with a function to do the handling:
|
||||
```clj
|
||||
(re-frame.core/reg-event-db ;; <-- call this to register handlers
|
||||
(re-frame.core/reg-event-db ;; <-- call this to register a handler
|
||||
:set-flag ;; this is an event id
|
||||
(fn [db [_ new-value] ;; this function does the handling
|
||||
(assoc db :flag new-value)))
|
||||
|
@ -136,7 +133,7 @@ replay, inserting extra events into it, etc, which ruins the process.
|
|||
|
||||
### The Other Problem
|
||||
|
||||
And there's another purity problem:
|
||||
And there's another kind of purity problem:
|
||||
```clj
|
||||
(reg-event-db
|
||||
:load-localstore
|
||||
|
@ -145,21 +142,20 @@ And there's another purity problem:
|
|||
(assoc db :defaults val))))
|
||||
```
|
||||
|
||||
It sources data from LocalStore.
|
||||
You'll notice it sources data from LocalStore.
|
||||
|
||||
So this handler has no side effect - it doesn't need to change the world - __but__ it does
|
||||
need to source data from somewhere other than its arguments - from somewhere
|
||||
outside of app-db or the event.
|
||||
Although this handler has no side effect - it doesn't need to change the world - it does
|
||||
need to source data from somewhere other than its arguments, which, in turn, means it isn't pure.
|
||||
|
||||
So, it isn't a pure function, and that leads to the normal problems.
|
||||
|
||||
### Effects And Coeffects
|
||||
|
||||
So there are [two concepts at play here](http://tomasp.net/blog/2014/why-coeffects-matter/):
|
||||
- **Effects** - what your event handler does to the world (aka side-effects)
|
||||
- **Coeffects** - the data your event handler requires from the world in order to do its computation (aka [side-causes](http://blog.jenkster.com/2015/12/what-is-functional-programming.html))
|
||||
- **Coeffects** - the data your event handler requires from the world in order
|
||||
to do its computation (aka [side-causes](http://blog.jenkster.com/2015/12/what-is-functional-programming.html))
|
||||
|
||||
We'll need a solution for both.
|
||||
We'll need a solution for both situations.
|
||||
|
||||
### Why Does This Happen?
|
||||
|
||||
|
@ -169,8 +165,8 @@ They have to implement the control logic of your re-frame app, and
|
|||
that means dealing with the outside, mutative world of servers, databases,
|
||||
windows.location, LocalStore, cookies, etc.
|
||||
|
||||
There's just no getting away from living in a mutative world, er,
|
||||
which sounds ominous. Is that it? Are we doomed to impurity?
|
||||
There's just no getting away from living in a mutative world,
|
||||
which sounds pretty ominous. Is that it? Are we doomed to impurity?
|
||||
|
||||
Well, luckily a small twist in the tale makes a profound difference. We
|
||||
will look at side-effects first. Instead of creating event handlers
|
||||
|
@ -178,7 +174,7 @@ which *do side-effects*, we'll instead get them to *cause side-effects*.
|
|||
|
||||
### Doing vs Causing
|
||||
|
||||
Above, I proudly claimed that this `fn` event handler was pure:
|
||||
Above, I proudly claimed that this event handler was pure:
|
||||
```clj
|
||||
(reg-event-db
|
||||
:my-event
|
||||
|
@ -245,7 +241,7 @@ Here is an impure, side effecting handler:
|
|||
(reg-event-db
|
||||
:my-event
|
||||
(fn [db [_ a]]
|
||||
(dispatch [:do-something-else 3]) ;; Eeek, side-effect
|
||||
(dispatch [:do-something-else 3]) ;; <-- Eeek, side-effect
|
||||
(assoc db :flag true)))
|
||||
```
|
||||
|
||||
|
@ -284,7 +280,7 @@ The impure way:
|
|||
(assoc db :flag true)))
|
||||
```
|
||||
|
||||
the pure, descriptive way:
|
||||
the pure, descriptive alternative:
|
||||
```clj
|
||||
(reg-event-fx
|
||||
:my-event
|
||||
|
@ -315,17 +311,18 @@ It is now time to name that first argument:
|
|||
```clj
|
||||
(reg-event-fx
|
||||
:my-event
|
||||
(fn [coeffects event] ;; <--- thy name be coeefects
|
||||
(fn [cofx event] ;; <--- thy name be cofx
|
||||
{ ... }))
|
||||
```
|
||||
|
||||
When you use the `-fx` form of registration, the first argument of your handler will be a coeffects map.
|
||||
When you use the `-fx` form of registration, the first argument of your handler will be a map of coeffects which we name `cofx`.
|
||||
|
||||
In that map will be the complete set of "inputs" required by your function. The complete
|
||||
set of computational resources (data) needed to perform its computation. But how?
|
||||
I'll explain in an upcoming tutorial, I promise, but for the moment, take it as a magical given.
|
||||
This is will explained in an upcoming tutorial, I promise, but for the moment,
|
||||
take it as a magical given.
|
||||
|
||||
One of the keys in `coeffects` will likely be `:db` and that will be the value of `app-db`.
|
||||
One of the keys in `cofx` will likely be `:db` and that will be the value of `app-db`.
|
||||
|
||||
Remember this impure handler from before:
|
||||
```clj
|
||||
|
@ -340,14 +337,14 @@ We'd now rewrite that as a pure handler, like this:
|
|||
```clj
|
||||
(reg-event-fx ;; notice the -fx
|
||||
:load-localstore
|
||||
(fn [coeffect _] ;; coeffect is a map containing inputs
|
||||
(let [defaults (:defaults-key coeffect)] ;; <-- use it here
|
||||
{:db (assoc (:db coeffects) :defaults defaults)}))) ;; returns effects map
|
||||
(fn [cofx _] ;; cofx is a map containing inputs
|
||||
(let [defaults (:defaults-key cofx)] ;; <-- use it here
|
||||
{:db (assoc (:db cofx) :defaults defaults)}))) ;; returns effects map
|
||||
```
|
||||
|
||||
So, by some magic, not yet revealed, LocalStore will be queried before
|
||||
this handler runs and the required value from it will be placed into
|
||||
`coeffects` under the key `:localstore` for the handler to use.
|
||||
`cofx` under the key `:localstore` for the handler to use.
|
||||
|
||||
That process leaves the handler itself pure because it only sources data from arguments.
|
||||
|
||||
|
@ -368,7 +365,7 @@ Just to be clear, the following two handlers achieve exactly the same thing:
|
|||
(fn [db [_ new-value]
|
||||
(assoc db :flag new-value)))
|
||||
```
|
||||
and
|
||||
vs
|
||||
```clj
|
||||
(reg-event-fx
|
||||
:set-flag
|
||||
|
|
|
@ -12,8 +12,6 @@ make side effects a noop in event replays.
|
|||
|
||||
## Table Of Contexts
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Table Of Contexts](#table-of-contexts)
|
||||
- [Effects](#effects)
|
||||
* [Where Effects Come From](#where-effects-come-from)
|
||||
* [The Effects Map](#the-effects-map)
|
||||
|
@ -55,12 +53,12 @@ An effects map contains instructions.
|
|||
|
||||
Each key/value pair in the map is one instruction - the `key` uniquely identifies
|
||||
the particular side effect required, and the `value` for that `key` provides
|
||||
further data. The structure of the `value` varies on a per side-effect basis.
|
||||
further data. The structure of the `value` is different for each side-effect.
|
||||
|
||||
Here's the two instructions from the example above:
|
||||
```cljs
|
||||
{:db (assoc db :flag a) ;; side effect on app-db
|
||||
:dispatch [:do-something-else 3]} ;; dispatch this event
|
||||
{:db (assoc db :flag a) ;; side effect on app-db
|
||||
:dispatch [:do-something-else 3]} ;; dispatch this event
|
||||
```
|
||||
|
||||
That `:db` `key` instructs that "app-db" should be `reset!` to the
|
||||
|
@ -84,8 +82,8 @@ queries? Or what if you want to send logs to Logentries or metrics to DataDog.
|
|||
Or write values to windows.location. And what happens if your database is
|
||||
X, Y or Z?
|
||||
|
||||
The list of effects is long and varied, with everyone using a
|
||||
different combination of them.
|
||||
The list of effects is long and varied, with everyone needing to use a
|
||||
different combination.
|
||||
|
||||
So effect handling has to be extensible. You need to a way to define
|
||||
your own side effects.
|
||||
|
@ -104,11 +102,11 @@ Use it like this:
|
|||
))
|
||||
```
|
||||
|
||||
__<1>__ the key for the effect. When an effects map contains
|
||||
the key `:butterfly`, the registered function will be used to action it. <br>
|
||||
__<1>__ the key for the effect. When later an effects map contains
|
||||
the key `:butterfly`, the function we are registering will be used to action it. <br>
|
||||
|
||||
__<2>__ the function which actions the side effect. It will be called
|
||||
with one argument - the value for this key, in the effects map.
|
||||
__<2>__ the function which actions the side effect. Later, it will be called
|
||||
with one argument - the value in the effects map, for this key.
|
||||
|
||||
So, if an event handler returned these effects:
|
||||
```clj
|
||||
|
@ -179,7 +177,7 @@ Example: if your event handler registration looked like this:
|
|||
(reg-event-fx
|
||||
:some-id
|
||||
[debug (path :right)] ;; <-- two interceptors, apparently
|
||||
(fn [coeffect]
|
||||
(fn [cofx _]
|
||||
{}) ;; <-- imagine returned effects here
|
||||
```
|
||||
|
||||
|
@ -240,7 +238,7 @@ Some effects have no associated data:
|
|||
{:exit-fullscreen nil})) ;; <--- no data, use a nil
|
||||
```
|
||||
|
||||
So in these cases, although it looks odd, just supply `nil` as the value for this key.
|
||||
In these cases, although it looks odd, just supply `nil` as the value for this key.
|
||||
|
||||
The associated effect handler would look like:
|
||||
```clj
|
||||
|
@ -264,11 +262,6 @@ Want to stub out the `:dispatch` effect? Do this:
|
|||
(fn [_] )) ;; a noop
|
||||
```
|
||||
|
||||
XXX talk about reinstating:
|
||||
- capture return
|
||||
- XXX new feature?
|
||||
|
||||
|
||||
## Builtin Effect Handlers
|
||||
|
||||
#### :dispatch-later
|
||||
|
|
|
@ -4,8 +4,6 @@ This is an interceptors tutorial.
|
|||
|
||||
## Table Of Contents
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Table Of Contents](#table-of-contents)
|
||||
- [Interceptors](#interceptors)
|
||||
* [Why Interceptors?](#why-interceptors-)
|
||||
* [What Do Interceptors Do?](#what-do-interceptors-do-)
|
||||
|
@ -14,12 +12,12 @@ This is an interceptors tutorial.
|
|||
* [Show Me](#show-me)
|
||||
* [Handlers Are Interceptors Too](#handlers-are-interceptors-too)
|
||||
- [Executing A Chain](#executing-a-chain)
|
||||
* [The Links](#the-links)
|
||||
* [The Links Of The Chain](#the-links-of-the-chain)
|
||||
* [What Is Context?](#what-is-context-)
|
||||
* [Self Modifing](#self-modifing)
|
||||
* [Self Modifying](#self-modifying)
|
||||
* [Credit](#credit)
|
||||
* [Write An Interceptor](#write-an-interceptor)
|
||||
* [Wrapping Handlers](#wrapping-handlers)
|
||||
+ [Wrapping Handlers](#wrapping-handlers)
|
||||
- [Summary](#summary)
|
||||
- [Appendix](#appendix)
|
||||
* [The Builtin Interceptors](#the-builtin-interceptors)
|
||||
|
@ -35,11 +33,10 @@ Interceptors can look after "cross-cutting" concerns like undo, tracing and vali
|
|||
They help us to factor out commonality, hide complexity and introduce further steps into the "Derived Data,
|
||||
Flowing" story promoted by re-frame.
|
||||
|
||||
So, you'll want to use Interceptors - they're helpful.
|
||||
So, you'll want to use Interceptors because they solve problems, and help you to write nice code.
|
||||
|
||||
__Second__, under the covers, Interceptors are the means by which
|
||||
event handlers are executed (when you `dispatch`). You'll
|
||||
want to understand how that happens.
|
||||
__Second__, under the covers, Interceptors provide the mechanism by which
|
||||
event handlers are executed (when you `dispatch`). You they are central concept.
|
||||
|
||||
### What Do Interceptors Do?
|
||||
|
||||
|
@ -92,8 +89,8 @@ concept, right there.
|
|||
|
||||
### Show Me
|
||||
|
||||
You can provide a chain of interceptors when
|
||||
you register an event handler.
|
||||
At the time when you register an event handler, you can provide an
|
||||
chain of interceptors too.
|
||||
|
||||
Using a 3-arity registration function:
|
||||
```clj
|
||||
|
@ -111,7 +108,7 @@ Using a 3-arity registration function:
|
|||
You might see that registration above as associating `:some-id` with two things: (1) a chain of interceptors
|
||||
and (2) a handler.
|
||||
|
||||
Except, the handler is turned into an interceptor too. (We'll see how later)
|
||||
Except, the handler is turned into an interceptor too. (We'll see how shortly)
|
||||
|
||||
So `:some-id` is only associated with one thing: a 3-chain of interceptors,
|
||||
with the handler wrapped in an interceptor and put on the end of the other two.
|
||||
|
@ -121,16 +118,16 @@ and inserts its own interceptors
|
|||
(which do useful things) at the front (more on this soon too),
|
||||
so ACTUALLY, there's about 5 interceptors in the chain.
|
||||
|
||||
So, ultimately, that event registration associates the event id `some-id`
|
||||
So, ultimately, that event registration associates the event id `:some-id`
|
||||
with a chain of interceptors.
|
||||
|
||||
Later, when a `dispatch` for `:some-id` is done, that 5-chain of
|
||||
Later, when a `(dispatch [:some-id ...])` happens, that 5-chain of
|
||||
interceptors will be "executed". And that's how events get handled.
|
||||
|
||||
|
||||
## Executing A Chain
|
||||
|
||||
### The Links
|
||||
### The Links Of The Chain
|
||||
|
||||
Each interceptor has this form:
|
||||
```clj
|
||||
|
@ -177,7 +174,7 @@ respectively.
|
|||
|
||||
`:coeffects` will contain the inputs required by the event handler
|
||||
(sitting presumably on the end of the chain). So that's
|
||||
data like the `:event` being processed, and the initial state of `db`. These are .
|
||||
data like the `:event` being processed, and the initial state of `db`.
|
||||
|
||||
The handler-returned side effects are put into `:effects` including,
|
||||
but not limited to, new values for `db`.
|
||||
|
@ -185,16 +182,16 @@ but not limited to, new values for `db`.
|
|||
The first few interceptors in a chain (inserted by `reg-event-db`)
|
||||
have `:before` functions which __prime__ the `:coeffects`
|
||||
by adding in `:event`, and `:db`. Of course, other interceptors can
|
||||
add further to `:coeffect`. Perhaps the event handler needs
|
||||
add further to `:coeffects`. Perhaps the event handler needs
|
||||
data from localstore, or a random number, or a
|
||||
DataScript connection. Interceptors can build up the coeffect, via their
|
||||
DataScript connection. Interceptors can build up `:coeffects`, via their
|
||||
`:before`.
|
||||
|
||||
Equally, some interceptors in the chain will have `:after` functions
|
||||
which process the side effects accumulated into `:effects`
|
||||
including but, not limited to, updates to app-db.
|
||||
|
||||
### Self Modifing
|
||||
### Self Modifying
|
||||
|
||||
Through both stages (before and after), `context` contains a `:queue`
|
||||
of interceptors yet to be processed, and a `:stack` of interceptors
|
||||
|
@ -238,7 +235,7 @@ passive aggressive, understated thing it has going on!! Co-workers
|
|||
have said I'm "being overly sensitive", perhaps even horizontalist, but
|
||||
you can see it, right? Of course you can.
|
||||
|
||||
What a relief it would be to rid of it, but how? We'll write an interceptor: `trim-event`
|
||||
What a relief it would be to get rid of it, but how? We'll write an interceptor: `trim-event`
|
||||
|
||||
Once we have written `trim-event`, our registration will change to look like this:
|
||||
```clj
|
||||
|
@ -274,18 +271,18 @@ And, here it is:
|
|||
As you read this, look back to what a `context` looks like.
|
||||
|
||||
Notes:
|
||||
1. We use `->interceptor` to create an interceptor (but it just a map)
|
||||
1. We use `->interceptor` to create an interceptor (which is just a map)
|
||||
2. Our interceptor only has a `:before` function
|
||||
3. Our `:before` is given `context`. It modifies it and returns it.
|
||||
4. There is no `:after` for this Interceptor. It has nothing to do
|
||||
with the backwards processing flow of effects. It is concerned only
|
||||
with coeffects in the forward flow.
|
||||
with the backwards processing flow of `:effects`. It is concerned only
|
||||
with `:coeffects` in the forward flow.
|
||||
|
||||
####Wrapping Handlers
|
||||
#### Wrapping Handlers
|
||||
|
||||
We're going well. Let's do an advanced wrapping.
|
||||
|
||||
How would you wrap a handler in an interceptor?
|
||||
How would you wrap a handler in an Interceptor?
|
||||
|
||||
There's two kinds of handler:
|
||||
- the `-db` variety registered by `reg-event-db`
|
||||
|
@ -297,7 +294,7 @@ Let's do a `-db` variety. This is what a `-db` handler looks like:
|
|||
(assoc db :flag true)) ;; returns a new db
|
||||
```
|
||||
|
||||
And here is a function which turns a given handler into an interceptor:
|
||||
And here is a function which turns a `-db` handler into an interceptor:
|
||||
```clj
|
||||
(defn db-handler->interceptor
|
||||
[db-handler-fn]
|
||||
|
@ -315,7 +312,7 @@ And here is a function which turns a given handler into an interceptor:
|
|||
In this tutorial, we've learned:
|
||||
|
||||
__1.__ When you register an event handler, you can supply a collection of interceptors:
|
||||
```
|
||||
```clj
|
||||
(reg-event-db
|
||||
:some-id
|
||||
[in1 in2] ;; <--- a chain of 2 interceptors
|
||||
|
@ -323,12 +320,16 @@ __1.__ When you register an event handler, you can supply a collection of interc
|
|||
....)))
|
||||
```
|
||||
|
||||
__2.__ When you registering an event handler, you are associating an event id with a chain of interceptors including:
|
||||
- the ones your supply
|
||||
__2.__ When you are registering an event handler, you are associating an event id with a chain of interceptors including:
|
||||
- the ones your supply (optional)
|
||||
- an extra one on the end, which wraps the handler itself
|
||||
- a couple at the beginning of the chain, put there by the `reg-event-db` or `reg-event-fx`.
|
||||
|
||||
__3.__ Interceptors do interesting things:
|
||||
__3.__ An Interceptor Chain is executed in two stages. First a forwards sweep in which
|
||||
all `:before` functions are called, and then second, a backwards sweep in which the
|
||||
`:after` functions are called. A `context` will be threaded through all these calls.
|
||||
|
||||
__4.__ Interceptors do interesting things:
|
||||
- add to coeffects (data inputs to the handler)
|
||||
- process side effects (returned by a handler)
|
||||
- produce logs
|
||||
|
|
|
@ -7,19 +7,16 @@ to manage them in tests.
|
|||
|
||||
## Table Of Contexts
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Table Of Contexts](#table-of-contexts)
|
||||
- [Coeffects](#coeffects)
|
||||
* [What Are They?](#what-are-they-)
|
||||
* [An Example](#an-example)
|
||||
* [Let's Fix It](#let-s-fix-it)
|
||||
* [How We Want It](#how-we-want-it)
|
||||
* [How Are Coeffect Babies Made?](#how-are-coeffect-babies-made-)
|
||||
* [So, Next Step](#so--next-step)
|
||||
* [`coeffect` the function](#-coeffect--the-function)
|
||||
* [Other Example Uses of `coeffects`](#other-example-uses-of--coeffects-)
|
||||
* [`inject-cofx`](#-inject-cofx-)
|
||||
* [More `inject-cofx`](#more--inject-cofx-)
|
||||
* [Meet `reg-cofx`](#meet--reg-cofx-)
|
||||
* [Examples](#examples)
|
||||
* [The 4 Point Summary](#the-4-point-summary)
|
||||
* [The 5 Point Summary](#the-5-point-summary)
|
||||
* [Secret Interceptors](#secret-interceptors)
|
||||
* [Testing](#testing)
|
||||
|
||||
|
@ -43,7 +40,7 @@ DataScript connection.
|
|||
|
||||
### An Example
|
||||
|
||||
This handler obtains data directly from LocalStore
|
||||
This handler obtains data directly from LocalStore:
|
||||
```clj
|
||||
(reg-event-db
|
||||
:load-defaults
|
||||
|
@ -52,22 +49,24 @@ This handler obtains data directly from LocalStore
|
|||
(assoc db :defaults val))))
|
||||
```
|
||||
|
||||
Because it has accessed LocalStore, this event handler is not
|
||||
Because it has directly accessed LocalStore, this event handler is not
|
||||
pure, and impure functions cause well-documented paper cuts.
|
||||
|
||||
### How We Want It
|
||||
|
||||
Our goal in this tutorial is to rewrite this event handler so
|
||||
that data _only_ comes from the arguments.
|
||||
that data _only_ comes from the arguments.
|
||||
|
||||
Our first change is to start using `reg-event-fx` (instead of
|
||||
`reg-event-db`).
|
||||
To make this happen, our first change is to switch to
|
||||
using `reg-event-fx` (instead of `reg-event-db`).
|
||||
|
||||
Then we'll seek to have ALL the necessary extra data available in the
|
||||
first argument, typically called `coeffects`.
|
||||
Event handlers registered via `reg-event-fx` are slightly
|
||||
different to those registered via `reg-event-fx`. `-fx` handlers
|
||||
get two arguments, but the first is not `db`. Instead it is an argument which, in
|
||||
this tutorial, we will call `cofx` (that's a nice distinct name which will aid communication).
|
||||
|
||||
Previous tutorials have show us that we can obtain `:db` from
|
||||
`coeffects`. Well, not we want it to contain other useful data too.
|
||||
`cofx`. Well, in addition we now want it to contain other useful data too.
|
||||
```clj
|
||||
(reg-event-fx ;; note: -fx
|
||||
:load-defaults
|
||||
|
@ -77,36 +76,30 @@ Previous tutorials have show us that we can obtain `:db` from
|
|||
{:db (assoc db :defaults val))})) ;; returns an effect
|
||||
```
|
||||
|
||||
If we can find a way to achieve this, then we are back to
|
||||
writing pure event handlers.
|
||||
|
||||
But what must we do to data into cofx? How do we organise for it
|
||||
to contain a `:local-store` key, with the right value?
|
||||
Notice how `cofx` magically contains a `:local-store` key with the
|
||||
right value. How do we organise for this magic to happen?
|
||||
|
||||
### How Are Coeffect Babies Made?
|
||||
|
||||
Well, when two coeffects love each other very much ... no, stop ... this
|
||||
is a G-rated framework. Instead ...
|
||||
### Abracadabra
|
||||
|
||||
Each time an event handler is executed, a brand new `context` is created, and within that
|
||||
`context` is a brand new `:coeffect` map, which is initially totally empty.
|
||||
`context` is a brand new `:coeffect` map, which is initially totally empty.
|
||||
|
||||
That pristine `context` value (containing a pristine `:coeffect` map) is then threaded
|
||||
through a chain of Interceptors before it is finally handled to our event handler
|
||||
which will be sitting on the end of chain, itself wrapped up in an interceptor. We know
|
||||
through a chain of Interceptors before it is finally handled to our event handler,
|
||||
sitting on the end of a chain, itself wrapped up in an interceptor. We know
|
||||
this story well from a previous tutorial.
|
||||
|
||||
So, all members of the Interceptor chain have the opportunity to add to `:coeffects`
|
||||
via their `:before` function. This is where `:coeffect` gets made. This is where
|
||||
new keys are added to `:coeffect`, so that later our handler magically finds the
|
||||
right data in its parameter.
|
||||
via their `:before` function. This is where `:coeffect` magic happens. This is where
|
||||
new keys can be added to `:coeffect`, so that later our handler magically finds the
|
||||
right data (like `:local-store`) in its `cofx` argument.
|
||||
|
||||
### So, Next Step
|
||||
### Which Interceptors?
|
||||
|
||||
If Interceptors put data in `:coeffect`, then we'd better put the right ones on
|
||||
our handler when we register it.
|
||||
If Interceptors put data in `:coeffect`, then we'll need to add the right ones to
|
||||
our event handler when we register it.
|
||||
|
||||
This handler is the same as before, except for one addition:
|
||||
Something like this (this handler is the same as before, except for one addition):
|
||||
```clj
|
||||
(reg-event-fx
|
||||
:load-defaults
|
||||
|
@ -117,8 +110,9 @@ This handler is the same as before, except for one addition:
|
|||
{:db (assoc db :defaults val))}))
|
||||
```
|
||||
|
||||
So we've added one Interceptor. It will inject the right value into `context's` `:coeffeects`
|
||||
and that `:coeffects` ends up being the first parameter to our handler.
|
||||
So we've added one Interceptor and it will do the magic. It will inject the right
|
||||
value into `context's` `:coeffeects` which then goes on to be the first argument
|
||||
to our event handler (`cofx`)
|
||||
|
||||
|
||||
### `inject-cofx`
|
||||
|
@ -128,13 +122,11 @@ and that `:coeffects` ends up being the first parameter to our handler.
|
|||
It is a function which returns an Interceptor whose `:before` function loads
|
||||
a value into a `context's` `:coeffect` map.
|
||||
|
||||
|
||||
`inject-cofx` takes either one or two arguments. The first is always the `id` of the coeffect
|
||||
required (called a `cofx-id`). The 2nd is an optional addition value.
|
||||
.
|
||||
|
||||
So, in the case above, the `cofx-id` was `:local-store` and the additional value
|
||||
was "defaults-key" which was presumable the place to look in LocalStore
|
||||
was "defaults-key" which was presumably the LocalStore key.
|
||||
|
||||
### More `inject-cofx`
|
||||
|
||||
|
@ -153,9 +145,9 @@ So, if I wanted to, I could create an event handler which has access to 3 coeff
|
|||
... in here I can access cofx's keys :now :local-store and :random-int))
|
||||
```
|
||||
|
||||
Creating 3 coeffects for the one handler is probably just showing off, and not generally necessary.
|
||||
Adding 3 coeffects for the one handler is probably just showing off, and not generally necessary.
|
||||
|
||||
And so to the final piece in the puzzle. How does `inject-cofx` know what to do when
|
||||
And so, the final piece in the puzzle: how does `inject-cofx` know what to do when
|
||||
it is given `:now` or `:local-store` ? Each `cofx-id` requires a different action.
|
||||
|
||||
### Meet `reg-cofx`
|
||||
|
|
Loading…
Reference in New Issue