re-frame/src/re_frame/core.cljc

189 lines
6.7 KiB
Plaintext
Raw Normal View History

2015-02-25 11:03:02 +00:00
(ns re-frame.core
(:require
[re-frame.events :as events]
[re-frame.subs :as subs]
[re-frame.interop :as interop]
[re-frame.db :as db]
[re-frame.fx :as fx]
[re-frame.cofx :as cofx]
[re-frame.router :as router]
[re-frame.loggers :as loggers]
[re-frame.registrar :as registrar]
[re-frame.interceptor :as interceptor]
2016-08-08 05:17:01 +00:00
[re-frame.std-interceptors :as std-interceptors :refer [db-handler->interceptor
fx-handler->interceptor
ctx-handler->interceptor]]))
2015-02-25 11:03:02 +00:00
2016-07-13 14:32:36 +00:00
;; -- dispatch
(def dispatch router/dispatch)
(def dispatch-sync router/dispatch-sync)
2015-02-25 11:03:02 +00:00
2016-07-13 14:32:36 +00:00
2016-08-08 13:15:26 +00:00
;; XXX move API functions up to this core level - to enable code completion and docs
;; XXX on figwheel reload, is there a way to not get the re-registration messages.
;; -- interceptor related
2016-08-08 05:17:01 +00:00
;; useful if you are writing your own interceptors
(def ->interceptor interceptor/->interceptor)
(def enqueue interceptor/enqueue)
(def get-coeffect interceptor/get-coeffect)
(def get-effect interceptor/get-effect)
(def assoc-effect interceptor/assoc-effect)
(def assoc-coeffect interceptor/assoc-coeffect)
;; -- standard interceptors
2016-08-08 05:17:01 +00:00
(def debug std-interceptors/debug)
(def path std-interceptors/path)
(def enrich std-interceptors/enrich)
(def trim-v std-interceptors/trim-v)
(def after std-interceptors/after)
(def on-changes std-interceptors/on-changes)
2016-08-08 13:15:26 +00:00
;; -- subscriptions
(defn reg-sub-raw
2016-10-13 04:44:29 +00:00
"Associate a given `query id` with a given subscription handler function `handler-fn`
which is expected to take two arguments: app-db and query vector, and return
2016-08-27 13:38:25 +00:00
a `reaction`.
2016-10-21 01:01:32 +00:00
This is a low level, advanced function. You should probably be using reg-sub
instead."
[query-id handler-fn]
(registrar/register-handler subs/kind query-id handler-fn))
2016-08-04 07:08:08 +00:00
(def reg-sub subs/reg-sub)
(def subscribe subs/subscribe)
2015-02-25 11:03:02 +00:00
2016-08-08 13:15:26 +00:00
(def clear-sub (partial registrar/clear-handlers subs/kind))
2016-11-06 06:41:51 +00:00
(def clear-subscription-cache! subs/clear-subscription-cache!)
2016-08-08 13:15:26 +00:00
2016-08-08 05:17:01 +00:00
;; -- effects
2016-08-08 13:15:26 +00:00
(def reg-fx fx/register)
(def clear-fx (partial registrar/clear-handlers fx/kind))
2016-07-13 14:32:36 +00:00
2016-08-08 05:17:01 +00:00
;; -- coeffects
2016-08-08 13:15:26 +00:00
(def reg-cofx cofx/register)
(def inject-cofx cofx/inject-cofx)
2016-08-08 13:15:26 +00:00
(def clear-cofx (partial registrar/clear-handlers cofx/kind))
2016-07-13 14:32:36 +00:00
2016-08-08 13:15:26 +00:00
;; -- Events
(def clear-event (partial registrar/clear-handlers events/kind))
2016-07-13 14:32:36 +00:00
(defn reg-event-db
2016-08-08 05:17:01 +00:00
"Register the given `id`, typically a keyword, with the combination of
`db-handler` and an interceptor chain.
`db-handler` is a function: (db event) -> db
`interceptors` is a collection of interceptors, possibly nested (needs flattening).
`db-handler` is wrapped in an interceptor and added to the end of the chain, so in the end
2016-08-08 05:17:01 +00:00
there is only a chain.
The necessary effects and coeffects handler are added to the front of the
interceptor chain. These interceptors ensure that app-db is available and updated."
([id db-handler]
(reg-event-db id nil db-handler))
([id interceptors db-handler]
(events/register id [cofx/inject-db fx/do-fx interceptors (db-handler->interceptor db-handler)])))
(defn reg-event-fx
([id fx-handler]
(reg-event-fx id nil fx-handler))
([id interceptors fx-handler]
(events/register id [cofx/inject-db fx/do-fx interceptors (fx-handler->interceptor fx-handler)])))
2016-08-03 07:35:49 +00:00
(defn reg-event-ctx
2016-07-13 14:32:36 +00:00
([id handler]
2016-08-03 07:35:49 +00:00
(reg-event-ctx id nil handler))
([id interceptors handler]
(events/register id [cofx/inject-db fx/do-fx interceptors (ctx-handler->interceptor handler)])))
2015-04-26 21:38:37 +00:00
;; -- Logging -----
;; Internally, re-frame uses the logging functions: warn, log, error, group and groupEnd
;; By default, these functions map directly to the js/console implementations,
;; but you can override with your own fns (set or subset).
2016-06-03 02:58:06 +00:00
;; Example Usage:
;; (defn my-fn [& args] (post-it-somewhere (apply str args))) ;; here is my alternative
;; (re-frame.core/set-loggers! {:warn my-fn :log my-fn}) ;; override the defaults with mine
2016-06-24 12:09:07 +00:00
(def set-loggers! loggers/set-loggers!)
2016-07-19 04:33:52 +00:00
;; If you are writing an extension to re-frame, like perhaps
;; an effects handler, you may want to use re-frame logging.
2016-07-19 04:33:52 +00:00
;;
;; usage: (console :error "this is bad: " a-variable " and " anotherv)
;; (console :warn "possible breach of containment wall at: " dt)
2016-07-18 09:37:01 +00:00
(def console loggers/console)
2015-05-02 00:46:05 +00:00
;; -- State Restoration For Unit Tests
(defn make-restore-fn
"Checkpoints the state of re-frame and returns a function which, when
later called, will restore re-frame to that checkpointed state.
Checkpoint includes app-db, all registered handlers and all subscriptions.
"
[]
(let [handlers @registrar/kind->id->handler
2016-08-19 08:20:21 +00:00
app-db @db/app-db
subs-cache @subs/query->reaction]
(fn []
2016-08-19 08:20:21 +00:00
;; call `dispose!` on all current subscriptions which
;; didn't originally exist.
#_(->> subs/query->reaction
vals
(remove (set (vals subs-cache))) ;;
(map interop/dispose!)
(doall))
;; reset the atoms
(reset! subs/query->reaction subs-cache)
(reset! registrar/kind->id->handler handlers)
(reset! db/app-db app-db)
nil)))
2016-08-04 12:19:04 +00:00
;; -- Event Processing Callbacks
(defn add-post-event-callback
"Registers a function `f` to be called after each event is processed
`f` will be called with two arguments:
- `event`: a vector. The event just processed.
- `queue`: a PersistentQueue, possibly empty, of events yet to be processed.
This is useful in advanced cases like:
- you are implementing a complex bootstrap pipeline
- you want to create your own handling infrastructure, with perhaps multiple
handlers for the one event, etc. Hook in here.
- libraries providing 'isomorphic javascript' rendering on Nodejs or Nashorn.
'id' is typically a keyword. Supplied at \"add time\" so it can subsequently
be used at \"remove time\" to get rid of the right callback.
"
([f]
(add-post-event-callback f f)) ;; use f as its own identifier
([id f]
(router/add-post-event-callback re-frame.router/event-queue id f)))
(defn remove-post-event-callback
[id]
(router/remove-post-event-callback re-frame.router/event-queue id))
;; -- Deprecation Messages
;; Assisting the v0.0.7 -> v0.0.8 transition.
(defn register-handler
[& args]
2016-08-03 08:09:53 +00:00
(console :warn "re-frame: \"register-handler\" has been renamed \"reg-event-db\" (look for registration of " (str (first args)) ")")
(apply reg-event-db args))
(defn register-sub
[& args]
2016-08-09 00:18:22 +00:00
(console :warn "re-frame: \"register-sub\" is deprecated. Use \"reg-sub-raw\" (look for registration of " (str (first args)) ")")
(apply reg-sub-raw args))