101 lines
3.7 KiB
Org Mode
101 lines
3.7 KiB
Org Mode
#+TITLE: Minimal clojurescript reagent example
|
|
|
|
* Components
|
|
Reagent allow multiple ways to create components with increasing complexity.
|
|
There is some good info in this article.
|
|
https://purelyfunctional.tv/guide/reagent/
|
|
|
|
** Form 1 components
|
|
Form one components are for simply rendering some html with values that are not going to change.
|
|
|
|
In the example below the function just returns some hiccup with the parameters inserted, you need to specify =:key= when dynamically repeating the elements and these should be reproducible unique id's where possible not randomly generated or indexed numbers if the data is unordered.
|
|
#+BEGIN_SRC clojure :tangle "src/core.cljs"
|
|
(defn navbar-link [{:keys [href title text] :or {text nil title nil}}]
|
|
[:a.link.dim.dib.mr3 {:key href :href href :title title} text])
|
|
|
|
[navbar-link {:href "https://clojure.org" :title "linke title" :text "link here"}]
|
|
#+END_SRC
|
|
|
|
|
|
#+BEGIN_SRC clojure
|
|
(defn product-card
|
|
[{:keys [title amount description link]}]
|
|
[:article.br2.ba.dark-gray.b--black-10.ma2.w-100.w-50-m.w-25-l.mw5
|
|
[:img.db.w-100.br2.br--top {:src link}]
|
|
[:div.pa2.ph3-ns.pb3-ns
|
|
[:div.dt.w-100.mt1
|
|
[:div.dtc [:h1.f5.f4-ns.mv0 title]]
|
|
[:div.dtc.tr [:h2.f5.mv0 amount]]]
|
|
[:p.f6.lh-copy.measure.mt2.mid-gray description]]])
|
|
|
|
[:div.flex
|
|
[product-card
|
|
{:title "Cat 01"
|
|
:amount "£54.59"
|
|
:description "Cat 1 description here"
|
|
:link "http://placekitten.com/g/600/300"}]
|
|
[product-card
|
|
{:title "Cat 02"
|
|
:amount "£34.59"
|
|
:description "Cat 2 description here"
|
|
:link "http://placekitten.com/g/600/300"}]]
|
|
#+END_SRC
|
|
|
|
** Form 2 components
|
|
In form two we can track local state inside a component a click counter being a basic example.
|
|
|
|
#+BEGIN_SRC clojure
|
|
(defn my-component [title starting-value]
|
|
(let [local-state (reagent/atom starting-value)]
|
|
(fn [title]
|
|
[:h1 {:class (when @local-state "hide")
|
|
:on-click (fn [] (swap! local-state inc))}
|
|
(str title " " @local-state)])))
|
|
|
|
[my-component "Clickable component" 1]
|
|
#+END_SRC
|
|
|
|
** Form 3 components
|
|
This form of component give's you full access to the react life cycle methods, so render did-mount did-unmount etc
|
|
usually this form of component is only needed when rendering graphics or things like graphs, it's also useful for capturing errors and handling them as in the example below, which renders your components but if =component-did-catch= is trigger the error is caught and displayed instead.
|
|
|
|
#+BEGIN_SRC clojurescript
|
|
(defn err-boundary
|
|
[& children]
|
|
(let [err-state (reagent/atom nil)]
|
|
(reagent/create-class
|
|
{:display-name "ErrBoundary"
|
|
:component-did-catch (fn [err info]
|
|
(reset! err-state [err info]))
|
|
:reagent-render (fn [& children]
|
|
(if (nil? @err-state)
|
|
(into [:<>] children)
|
|
(let [[_ info] @err-state]
|
|
[:pre [:code (pr-str info)]])))})))
|
|
#+END_SRC
|
|
|
|
* Fetching a html element reference
|
|
If we wish to capture a node we can use =:ref= and store the result in an atom, we can then de reference the atom and call a method on the node using =aget=.
|
|
|
|
#+BEGIN_SRC clojurescript :results output
|
|
(defn example-ref-component [title]
|
|
(let [local-ref (reagent/atom nil)]
|
|
(fn [title]
|
|
[:div#example-ref-id.flex.items-center.justify-center.pa4.bg-lightest-blue.navy
|
|
{:ref #(reset! local-ref %)}
|
|
(str title (when @local-ref (aget @local-ref "id")))])))
|
|
|
|
[example-ref-component "Grabbing the element id using ref "]
|
|
#+END_SRC
|
|
|
|
|
|
* Further reading
|
|
|
|
https://github.com/reagent-project/reagent
|
|
|
|
https://purelyfunctional.tv/guide/reagent/#what-is-reagent
|
|
|
|
https://github.com/metosin/reitit
|
|
|
|
https://www.metosin.fi/blog/reitit/
|