söndag 5 april 2015

Terse explanation of re-frame

Re-frame is an single page web app event-loop machinery built on Reagent/React.js.

Application state app-db is stored in one (1) reagent atom.

By using reagent's reactions, one can build up a graph, chained reactions, where more costly operations can be "shielded" behind reactions which wont report a change if the reactions view from a new app-db is the same immutable data structure as it was in the previous app-db.

The redrawing of the DOM/screen is triggered by requestAnimationFrame. Given a standard refresh rate of 60 Hz, this trigger will occur every 16.67 ms, if the program is done with it's previous recalculation by then.

Re-frame uses hiccup-style syntax feed to the Reacts Virtual DOM.

There can be several related reagent atom-constructs called reactions, containing derived state ("views") of the app-state.

To make state changes in the application, initialization code or callback functions from event-emitters like the DOM, timers, network connections should send dispatch messages. These are put in a core.async channel and handled by registered handlers.

There's two special types of dispatch, dispatch-sync which handles the event directly, and does not put it in the core.async channel. The other special dispatch is putting ^:flush-dom metadata on the dispatched event, which doesn't wait for a requestAnimationFrame event before re-rendering the reactive data structures.

Events are sent as a very simple vector format. Like a lisp sexpression the first item of the vector should be a symbol (keyword) for which function (handler) that should be handling this sexpression (event). The rest of the vector is a free-form argument vector.

Handlers are registered with (register-sub :name-of-event handler-fn)

The handler-fn has the same purpose as a clojure reduce-function, its arguments are the app-state (derefed!) and the incoming event.

The handler-fn returns the new application-state, which re-frame will reset! into app-db.

Re-frame offers a simple middleware-abstraction, where debug/logging-statements can be put. Another powerful middleware is path, that works as a lens, making the handler-fn simpler by making it work on a specific path in the app-db.

I guess one could create some middleware for simplifying the use of datascript as application state atom.

The handler should implement the logic on what should happend to an incoming event, potentially based on the app-db state.  The re-frame readme mentions finite state machines as a fruitful abstraction.