mirror of
https://github.com/status-im/re-frame.git
synced 2025-02-23 07:18:22 +00:00
Coeffect docs improved
This commit is contained in:
parent
f4f1ffdca2
commit
c1b9859941
@ -2,7 +2,7 @@
|
||||
|
||||
This tutorial explains `coeffects`.
|
||||
|
||||
It explains what they are, how they help, how they can be "injected", and how
|
||||
It explains what they are, how they can be "injected", and how
|
||||
to manage them in tests.
|
||||
|
||||
## Table Of Contexts
|
||||
@ -49,24 +49,27 @@ This handler obtains data directly from LocalStore:
|
||||
(assoc db :defaults val))))
|
||||
```
|
||||
|
||||
This works, but there's a cost.
|
||||
|
||||
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 it __only__ uses data from arguments.
|
||||
|
||||
To make this happen, our first change is to switch to
|
||||
To make this happen, we first switch to
|
||||
using `reg-event-fx` (instead of `reg-event-db`).
|
||||
|
||||
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).
|
||||
get two arguments, but the first is not `db`. Instead it
|
||||
is an argument which 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
|
||||
`cofx`. Well, in addition we now want it to contain other useful data too.
|
||||
Previous tutorials showed there's a `:db` key in `cofx`. We
|
||||
now want `cofx` to have other keys and values:
|
||||
```clj
|
||||
(reg-event-fx ;; note: -fx
|
||||
:load-defaults
|
||||
@ -77,29 +80,29 @@ Previous tutorials have show us that we can obtain `:db` from
|
||||
```
|
||||
|
||||
Notice how `cofx` magically contains a `:local-store` key with the
|
||||
right value. How do we organise for this magic to happen?
|
||||
right value. How do we make this magic happen?
|
||||
|
||||
### 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.
|
||||
|
||||
That pristine `context` value (containing a pristine `:coeffect` map) is then threaded
|
||||
That pristine `context` value (containing a pristine `:coeffect` map) is threaded
|
||||
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` magic happens. This is where
|
||||
via their `:before` function. This is where `:coeffect` magic happens. This is how
|
||||
new keys can be added to `:coeffect`, so that later our handler magically finds the
|
||||
right data (like `:local-store`) in its `cofx` argument.
|
||||
right data (like `:local-store`) in its `cofx` argument. It is the Interceptors.
|
||||
|
||||
### Which Interceptors?
|
||||
|
||||
If Interceptors put data in `:coeffect`, then we'll need to add the right ones to
|
||||
our event handler when we register it.
|
||||
when we register our event handler.
|
||||
|
||||
Something like this (this handler is the same as before, except for one addition):
|
||||
Something like this (this handler is the same as before, except for one detail):
|
||||
```clj
|
||||
(reg-event-fx
|
||||
:load-defaults
|
||||
@ -110,17 +113,17 @@ Something like this (this handler is the same as before, except for one addition
|
||||
{:db (assoc db :defaults val))}))
|
||||
```
|
||||
|
||||
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
|
||||
So we've added one Interceptor. It will inject the right key/value pair
|
||||
into `context's` `:coeffeects` which then goes on to be the first argument
|
||||
to our event handler (`cofx`)
|
||||
|
||||
|
||||
### `inject-cofx`
|
||||
|
||||
`inject-cofx` is part of re-frame API.
|
||||
`inject-cofx` is part of re-frame API.
|
||||
|
||||
It is a function which returns an Interceptor whose `:before` function loads
|
||||
a value into a `context's` `:coeffect` map.
|
||||
a key/value pair 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.
|
||||
@ -130,13 +133,13 @@ was "defaults-key" which was presumably the LocalStore key.
|
||||
|
||||
### More `inject-cofx`
|
||||
|
||||
Here's some other examples of its use:
|
||||
Here's some other usage examples:
|
||||
|
||||
- `(inject-cofx :random-int 10)`
|
||||
- `(inject-cofx :guid)`
|
||||
- `(inject-cofx :now)`
|
||||
|
||||
So, if I wanted to, I could create an event handler which has access to 3 coeffects:
|
||||
I could create an event handler which has access to 3 coeffects:
|
||||
```clj
|
||||
(reg-event-fx
|
||||
:some-id
|
||||
@ -145,28 +148,30 @@ 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))
|
||||
```
|
||||
|
||||
Adding 3 coeffects for the one handler is probably just showing off, and not generally necessary.
|
||||
But that's probably just showing off, and not very useful.
|
||||
|
||||
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.
|
||||
And so, to 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`
|
||||
|
||||
Allows you associate a`cofx-id` (like `:now` or `:local-store`) with a
|
||||
handler function that injects the right data.
|
||||
This function is also part of the re-frame API.
|
||||
|
||||
It allows you associate a`cofx-id` (like `:now` or `:local-store`) with a
|
||||
handler function that injects the right key/value pair.
|
||||
|
||||
The function you register will be passed two arguments:
|
||||
- a `:coeffects` map, and
|
||||
- optionally, the additional value supplied
|
||||
and it is expected to return a modified `:coeffects` map, presumably with an
|
||||
added key and value.
|
||||
- a `:coeffects` map (to which it should add key/value pair), and
|
||||
- optionally, the additional value supplied to `inject-cofx`
|
||||
and it is expected to return a modified `:coeffects` map.
|
||||
|
||||
### Examples
|
||||
### Examples Of `reg-cofx`
|
||||
|
||||
Above we wrote an event handler that wanted `:now` data to be available. Here
|
||||
is how a handler could be registered for `:now`:
|
||||
```clj
|
||||
(reg-cofx ;; uses this new registration function
|
||||
(reg-cofx ;; registration function
|
||||
:now ;; what cofx-id are we registering
|
||||
(fn [coeffects _] ;; second parameter not used in this case
|
||||
(assoc coeffects :now (js.Date.)))) ;; add :now key, with value
|
||||
@ -186,6 +191,36 @@ And there's this example:
|
||||
With these two registrations in place, I can now use `(inject-cofx :now)` and
|
||||
`(inject-cofx :local-store "blah")` in an effect handler's interceptor chain.
|
||||
|
||||
|
||||
### Secret Interceptors
|
||||
|
||||
In a previous tutorial we learned that `reg-events-db`
|
||||
and `reg-events-fx` add Interceptors to front of any chain
|
||||
during registration.We found they inserted an Interceptor called `do-fx`.
|
||||
|
||||
I can now reveal that
|
||||
they also add `(inject-cofx :db)` at the front of each chain.
|
||||
|
||||
Guess what that injects into the `:coeffects` of every event handler?
|
||||
|
||||
Okay, so that was the last surprise. Now you know everything.
|
||||
|
||||
### Testing
|
||||
|
||||
During testing, you may want to mock certain coeffets.
|
||||
|
||||
You may, for example, want to test that an event handler works
|
||||
using a specific `random number`, not a true random number.
|
||||
|
||||
In your test, you'd mock out the cofx handler:
|
||||
```
|
||||
(reg-cofx
|
||||
:random-int
|
||||
(fn [coeffects _]
|
||||
(assoc coeffects :random-int 5))) ;; 5 is not very random
|
||||
```
|
||||
|
||||
|
||||
### The 5 Point Summary
|
||||
|
||||
In note form:
|
||||
@ -193,29 +228,7 @@ In note form:
|
||||
1. Event handlers should only source data from their arguments
|
||||
2. We want to "inject" required data into the first, cofx argument
|
||||
3. We use the `(inject-cofx :key)` interceptor in registration of the event handler
|
||||
4. It will the registered cofx handler for that `:key` to do the injection
|
||||
4. It will look up the registered cofx handler for that `:key` to do the injection
|
||||
5. We must have previously registered a cofx handler via `reg-cofx`
|
||||
|
||||
|
||||
### Secret Interceptors
|
||||
|
||||
In a previous tutorial we learned that `reg-events-db`
|
||||
and `reg-events-fx` add Interceptors to front of any chain during registration.
|
||||
|
||||
We found they inserted an Interceptor called `do-fx`. I can now reveal that
|
||||
they also add `(inject-cofx :db)` at the front of each chain.
|
||||
|
||||
Guess what that injects into the `:coeffects` of every event handler?
|
||||
|
||||
Okay, so that was the last surprise. Now you know everything. Hopefully
|
||||
the pizzle pieces fit nicely together
|
||||
|
||||
### Testing
|
||||
|
||||
During testing, you may want to stub out certain coeffets.
|
||||
|
||||
You may, for example, want to test that an event handler works
|
||||
using a specific `random number`.
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user