Skip to content

A minimal zero-deps Reagent-like for Squint and CLJS

Notifications You must be signed in to change notification settings

borkdude/reagami

Repository files navigation

Reagami

npm

Fold your state into the DOM!

A minimal zero-deps Reagent-like in Squint and CLJS.

Usage

Quickstart example:

(ns my-app
  (:require ["https://esm.sh/reagami" :as reagami]))

(def state (atom {:counter 0}))

(defn my-component []
  [:div
   [:div "Counted: " (:counter @state)]
   [:button {:on-click #(swap! state update :counter inc)}
    "Click me!"]])

(defn render []
  (reagami/render (js/document.querySelector "#app") [my-component]))

(add-watch state ::render (fn [_ _ _ _]
                            (render)))

(render)

(Open this example on the Squint playground)

In ClojureScript you would add this library to your deps.edn :deps as follows:

io.github.borkdude/reagami {:git/sha "<latest-sha>" :git/tag "<latest-tag>"}

and then require it with (:require [reagami.core :as reagami]).

Reagami supports:

  • Building small reactive apps with the only dependency being Squint or CLJS. Smallest app with Squint after minification is around 5kb gzip.
  • Rendering hiccup into a container DOM node. The only public function is render.
  • Event handlers via :on-click, :on-input, etc.
  • Default attributes: :default-value, etc. for uncontrolled components
  • Id and class short notation: [:div#foo.class1.class2]
  • Disabling properties with false: [:button {:disabled (not true)}]
  • :style maps: {:style {:background-color :green}}
  • :on-render hook. See docs here.

Reagami does NOT support:

  • Auto-rerendering by auto-watching custom atoms. Instead you use add-watch + render on regular atoms or you call render yourself.
  • React hooks (it doesn't use React)

Local state can be accomplished by using nested renders like in this example or using web components.

Reagami uses a basic patching algorithm explained in this blog post. It may become more advanced in the future, but the (fun) point of this library at this point is that it's small, underengineered and thus suited for educational purposes.

For a more fully featured version of Reagent in squint, check out Eucalypt.

:on-render

The :on-render hook can be used to do something after a DOM node is mounted, updated or unmounted. It takes 3 arguments: (fn [node lifecycle data])

  • node: the DOM node that is mounted, updated or unmounted.
  • lifecycle: one of :mount, :update or :unmount
  • data: the result of the :on-render function every time it is called. By returning data you can pass data from one lifecycle to another. E.g. when you mount a JS component, you can return {:unmount unmount} so you can call the unmount function in the :unmount lifecycle.

Example:

(fn [node lifecycle {:keys [unmount updates] :as data}]
  (case lifecycle
    :mount
    {:unmount (install-clock! node)
     :updates 0}

    :update
    (update data :updates inc)

    :unmount
    (do
      (println "Number of updates in total: " updates)
      (unmount))))

See a full working example on the playground.

Examples

Examples on the Squint playground:

License

MIT

About

A minimal zero-deps Reagent-like for Squint and CLJS

Topics

Resources

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published