Skip to content

Commit

Permalink
Update Flows.md
Browse files Browse the repository at this point in the history
  • Loading branch information
mike-thompson-day8 authored Nov 1, 2023
1 parent cf270e4 commit 52dc46d
Showing 1 changed file with 21 additions and 9 deletions.
30 changes: 21 additions & 9 deletions docs/Flows.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
> We'd love to hear your feedback!
> Please join our discussions on [github](https://github.com/day8/re-frame/discussions/795) and [slack](https://clojurians.slack.com/archives/C073DKH9P/p1698792674379499).
---

> 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
metalwork, a little refreshing of the ornamentation ... but is this not the nine hundred-year-old
axe of my family? And because it has changed gently over time, it is still a pretty good axe,
y'know. Pretty good.

> -- Terry Pratchett, The Fifth Elephant <br>
> &nbsp;&nbsp;&nbsp; reflecting on identity, flow and derived values (aka [The Ship of Theseus](https://en.wikipedia.org/wiki/Ship_of_Theseus))
<br/>
<br/>
## The Story So Far

1. **Users** cause **Events**
Expand All @@ -11,7 +24,7 @@

## Flows

This tutorial introduces a feature called `Flows`, which is a part of step 3 - a later stage in step 3, call it step 3.b.
This tutorial introduces a feature called `Flows`, a trailing part of step 3 - call it step 3.b.
`re-frame's` tagline is "derived values, flowing" and, well, `Flows` helps data to flow.

## Flows
Expand All @@ -29,7 +42,7 @@ re-frame `flows` are registered using the API function `reg-flow`. You call it

## Flow Specification

It is just a map. Here's an example which automatically calculates the `area` of a room from `width` and `height`:
It is just a map. Here's an example specification to automatically calculate the `area` of a room from `width` and `height`:

<div class="cm-doc" data-cm-doc-no-result>
{:id :room-area
Expand All @@ -42,10 +55,10 @@ It is just a map. Here's an example which automatically calculates the `area` of

Notes:
- `:inputs` is a mapping from keywords to `app-db` paths
- When the values at the `:inputs` paths change, the `:output` function is called to calculate a new derived value. It is called with two args:
- the previously calculated derived value
- a map with the same keys as `:inputs`, and for each the current value at the path. So, in the example above, it is `:w` and `:h` keys.
- The newly calculated derived value (`width` - the output of the function call) is put back into `app-db` at `:path`
- When the values at the `:inputs` paths change, the an `:output` function is called to calculate a new derived value. It is called with two args:
- any previously calculated derived value
- a map with the same keys as `:inputs` and, for each, the current value from `app-db` at that path.
- The newly calculated derived value (`width` in the example - the output of the function call) is put back into `app-db` at `:path`

## When Does This All Happen?

Expand All @@ -55,15 +68,15 @@ So, because of Flows, effects to `app-db` can cause further effects to `app-db`.

## A Basic Example

To shows `Flows` in action, let's do some live coding. First, we add the necessary `requires` (`reg-flow` is still in the `alpha` namespace):
To show `Flows` in action, let's do some live coding. First, we add the necessary `requires` (`reg-flow` is still in the `alpha` namespace):

<div class="cm-doc">
(ns re-frame.example.flows
(:require [re-frame.alpha :as rf]
[reagent.dom.client :as rdc]))
</div>

Now, let's use our flow in a simple app. The user can enter `height` and `width` and in response, they see `area`:
Here's our app: the user can enter `height` and `width` values and, in response, they see `area`:

<div class="cm-doc">
(rf/reg-sub :width (fn [db _] (get-in db [:kitchen :width])))
Expand Down Expand Up @@ -158,7 +171,6 @@ In this sense, they are redundant. Rather than use a flow, you could simply call

This works just fine... *or does it*? Actually, we forgot to change the `:length` event. Our area calculation will be wrong every time the user changes the length! Easy to fix, but the point is that we had to fix it at all. How many events will we need to review? In a mature app, this is not a trivial question.

Furthermore, is this really a `:width` event any more? Now it's more of a `:with-and-area` event. Flows can help keep concerns separate, avoiding this kind of semantic creep.

*Design is all tradeoffs*. Flows allow us to say "This value simply derives from these inputs. It simply changes when they do." We do this at the expense of some "spooky action at a distance" - in other words, we accept that no particular event will be responsible for that change.

Expand Down

0 comments on commit 52dc46d

Please sign in to comment.