Liking cljdoc? Tell your friends :D

Authoring components

hx doesn't do anything special in regards to how it calls or creates React components. They are assumed to act like native, vanilla React components that could be used in any codebase.

In practice, this is fairly easy to handle in ClojureScript. A basic functional component can be written as just a normal function that returns a React element:

(defn MyComponent [props]
  (hiccup/parse [:div "Hello"]))
  
(react-dom/render (hiccup/parse [MyComponent]) (. js/document getElementById "app"))

props will always be a JS object, so if we want to pull something out of it, we'll need to use JS interop:

(defn MyComponent [props]
  (let [name (goog.object/get props "name")]
    (hiccup/parse [:div "Hello, " name "!"]))
    
(react-dom/render (hiccup/parse [MyComponent {:name "Uma"}])
                  (. js/document getElementById "app"))

hx.react/defnc is a macro that shallowly converts the props object for us and wraps our function body in hiccup/parse, so we can get rid of some of the boilerplate:

(hx/defnc MyComponent [{:keys [name]}]
  [:div "Hello, " name "!"])

Children are also passed in just like any other prop, so if we want to obtain children we simply peel it off of the props object:

(defn HasChildren [props]
  (let [children (goog.object/get props "children")]
    (hiccup/parse
      [:div 
       {:style {:border "1px solid #000"}}
       children]))

;; or
(hx/defnc HasChildren [{:keys [children]}]
  [:div
   {:style {:border "1px solid #000"}}
   children])

defnc has one other tricks up it's sleeve. It can take a map of options as it's first element of the body, just like defn:

(hx/defnc HasOptions [_]
  {:pre [(true? true)]
   :post [(not false)]
   :wrap [with-router
          with-theme]}
  [:div "Foo"])

The current list of options which can be passed in are:

  • :pre which acts like defn's :pre
  • :post which acts like defn's :post
  • :wrap which takes a collection of higher-order components and returns a component wrapped in all of them, like (-> HasOptions with-router with-theme)

Lifecycle

Sometimes we also need access to React's various lifecycle methods like componentDidMount, componentDidUpdate, etc. In that case, we should create a React component class. hx exposes a very barebones hx/defcomponent macro that binds closely to the OOP, class-based API React has for maximum flexibility. You can also leverage libraries like Om.Next, Reagent, Rum, or other frameworks that have state management built in.

Note though that React Hooks takes away most, if not all of the need to use the class-based React lifecycle methods, in a very nice and functional way that meshes very well with ClojureScript. The official documentation has an excellent getting starte guide.

Can you improve this documentation? These fine people already did:
Will Acton & Orestis Markou
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close