This is a doodle about a re-frame idea that's been rattling around in my head for a few days. It hasn't quite clicked, but I don't want to let it go yet.
I propose a new standard effect
.
Currently, re-frame has the :db
effect which replaces what's in app-db
holus-bolus.
Imagine a new effect named, say: :db-crud
.
You would use :db-crud
instead of :db
.
The value of :db-crud
would be a vector of proposed changes to app-db
. Update this. Delete that. Add another.
Imagine:
{:db-crud [{:add [:some :path] :val 2}
{:del [:a :path]}
{:upd [:a :b 2 :c] :val "hello"}]
The format used is not very important right now. The sketch above is just for flavour.
Question: why do it this way?
Answer: more information
When you use :db
to make a complete app-db
change, you pass on one piece of information - state has changed.
But you don't say what, how or why.
A :db-crud
effect says more. It says what path(s) changed, and how. It could even say (somehow)
"why" the path changed, maybe. More information.
So, how could this additional information be useful?
Assume we could look at the nominated paths looking for matches
(maybe using something like meander)
On finding a match we could, what? ...
- rerender?
- dispatch an event ?
- compute further app-db crud?
A simpler, less pure variation of alex-dixon's precept?
This information could be used like a database WAL. Or a Kafka-like, event-sourcing bus-ish thingo.
There's a good, useful idea lurking in here, I think.
But ... the key is working out what useful thing can be done with the "extra information".
Every bit of flexibility is potentially useful, yes, but it always comes with a cost. I'm still trying to figure out the tangible benifit.
One possible defect of :db-crud (which would be shared with the original :db efffect) is that updates express the final desired state, and not the actual programmer intent.
It's the same reason why
clojure.core/swap!
is preferrable toclojure.core/reset!
the former is safer to use in concurrent programming, and it expresses the intent of updating, rather than expressing a final result (which provenance might not be so immediately clear in comparison, and which value would be less useful in an event log).So, the following might could be better:
Note that my :assoc-in and :dissoc-in are essentially equivalent to :add and :del. But they help make more evident whether :update-in would have been better, by using an homogeneous and familiar api (given the
clojure.core/*-in
functions)Is
{:update-in [:b] inc}
a glorified version of(clojure.core/update-in [:b] inc)
? Yes, but 'glorified function calls' are common/necessary in reactive frameworks (e.g. Redux actions,re-frame.core/dispatch
).