Skip to content

Instantly share code, notes, and snippets.

@tomconnors
Created November 17, 2020 15:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomconnors/bd3fb275f893a3f16295c2ca93a32b2d to your computer and use it in GitHub Desktop.
Save tomconnors/bd3fb275f893a3f16295c2ca93a32b2d to your computer and use it in GitHub Desktop.
Integration of re-frame and react hooks.
(ns app.hooks
(:require
;; A lib provided by react to make these types of integrations easier:
["use-subscription" :as react.use-subscription]
[re-frame.interop :as rf.interop]
[re-frame.core :as rf]
[helix.hooks :as h.hooks] ; cljs wrapper of the react hooks api
))
(defn- maybe-dispose! [^clj reaction]
(when-not (seq (.-watches reaction))
(rf.interop/dispose! reaction)))
(let [n (atom 0)] ;; incremented int used to get unique keys for add-watch.
(defn use-sub [query]
(let [rf-sub (h.hooks/use-memo [query]
(let [r (rf/subscribe query)
;; If the reaction isn't set to autorun,
;; watches won't fire when the reaction is "dirty".
;; Reactions get "dirty" when their inputs change.
;; Setting :auto-run also seems to avoid an
;; issue where derefs
;; trigger setState calls in /other/ components
;; that subscribe to the same query.
;; React warns about this:
;; https://github.com/facebook/react/issues/18178
_ (._set-opts ^clj r {:auto-run true})]
r))
sub (h.hooks/use-memo [rf-sub]
#js{:getCurrentValue (fn []
;; Get rid of any reactive context
;; because we don't want
;; tracking of this deref.
(binding [ratom/*ratom-context* nil]
@rf-sub))
:subscribe (fn [callback]
(let [k (str "use-sub-" (swap! n inc))]
(add-watch rf-sub k callback)
(fn []
(remove-watch rf-sub k)
(maybe-dispose! rf-sub))))})]
(react.use-subscription/useSubscription sub))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment