React-bootstrap + reagent in shadow-cljs

I am trying to find any resources regarding usage of react-bootstrap with reagent in shadow-cljs. Unfortunately, all resources I’ve been able to find were focusing on cljsjs/reagent.

What I’ve been able to achieve so far is syntax like suggested for CLJS here: https://code.thheller.com/blog/shadow-cljs/2017/10/14/bootstrap-support.html

(ns test.main
  (:require ["react-bootstrap" :as bs]
            [reagent.core :as r]))

(def alert (r/adapt-react-class (aget bs "Alert")))
(def button (r/adapt-react-class (aget bs "Button")))

(defn home-page []
  [:div [:h2 "Welcome to reagent-test"]
   [alert {:bs-style "warning"} "foo"]
   [button "foo"]
   ])

Although it is working, is it still considered valid for shadow-cljs? This adapt-react-class syntax feel a bit redundant to me and I’d rather expect something like:

(defn home-page []
  [:div [:h2 "Welcome to reagent-test"]
   [bs/Alert {:bs-style "warning"} "foo"]])

But keeping my expectations aside - what’s the correct way of working with reagent and react-bootstrap in shadow-cljs? Thanks!

AFAIK shadow-cljs is agnostic as to which React wrapper you’re using. The syntax you mentioned is Reagent/React interop, not ClojureScript/JavaScript interop.

To answer you question, you’re using the component correctly. There’s a different style that is a bit more concise:

(ns test.main
  (:require ["react-bootstrap" :as bs]
            [goog.object :as gobj]
            [reagent.core :as r]))

(defn home-page []
  [:> (gobj/get bs "Alert") {:bs-style "warning"} "foo"])

;; or even

(defn home-page []
  [:> (.-Alert bs) {:bs-style "warning"} "foo"])

The special :> operator is described in the the Reagent docs.

This :> syntax still seems quite obvious - is there any reason why there is no function like:

(defn rbs [x] (r/adapt-react-class (aget bs x)))

(defn home-page []
  [:div [:h2 "Welcome to reagent-test"]
   [(rbs "Alert") {:bs-style "warning"} "bar"]])

Edit:
And why you’d choose gobj/get over aget?

You do not have to use gobj/get or aget in either case.

(ns test.main
  (:require ["react-bootstrap" :as bs]
            [reagent.core :as r]))

(defn home-page []
  [:div [:h2 "Welcome to reagent-test"]
   [:> bs/Alert {:bs-style "warning"} "foo"]
   [:> bs/Button "foo"]
   ])

This should work fine. When using adapt-react-class you must do this statically (as a def) since it would otherwise do this for every render which would cause react to re-render every frame since the component type “changed”, since a new class was created.

(def alert (r/adapt-react-class bs/Alert))
(def button (r/adapt-react-class bs/Button))

This however is purely dependent on reagent and not specific to shadow-cljs in any way. :> I believe is just syntax for “render native JS component” so you don’t have to adapt-react-class.

I like [:> bs/Alert] syntax - but how to use it in cases like [:> (aget bs "Navbar" "Header")?

Just use dots. [:> bs/Navbar.Header]

Now it’s clear. Thanks!

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.