Using React Native Components in ClojureScript

July 24, 2015

React iOS is beginning to develop a rich third-party component ecosystem. This post explains how to consume these components from Om / ClojureScript, using the ClojureScript tooling as it exists today (without full CommonJS / JSX support for React Native).

The main trick involves passing the correct module ID to js/require, as will be seen below. Otherwise there are no real difficulties.

For our example, let's use the react-native-swiper component by 斯人 (leecade) within the AwesomeProject example as modified for ClojureScript per the Ambly Wiki.

Install the Component

We first follow the instructions for installing the component as if we were not using ClojureScript at all. For our example component, we run

npm i react-native-swiper --save

but when following the instructions, we will only add this snipped to index.ios.js:

var Swiper = require('react-native-swiper')

Note that this needs to remain in index.ios.js in order to cause the React Native packager to bundle this dependency.

Determine the Module ID

With that line in place, if we launch our iOS app, and in a browser view the bundled JavaScript by navigating to http://localhost:8081/index.ios.bundle, we can find the following line in the emitted bundle. The string being passed to (React Native's) require is the module ID.

var Swiper=require('react-native-swiper/dist/index');

Note: If you consult the implementation of the React Native packager, you'll see that the module ID is normally formed as the module's name followed by the relative path from the module's root directory to the main JavaScript file (omitting filename extensions). If the module's name is unavailable, then the full path is used instead.

But, instead of trying to reverse-engineer the packager, I find it is easiest to simply peek inside the bundled output to obtain the module ID. To be honest, I haven't tracked down all cases and am not yet convinced it is worthwhile doing so. An example I haven't been able to explain is Brent Vatne's react-native-linear-gradient, which ends up with a module ID of 'LinearGradient'. Just cheat and take a look at the bundle output instead!

Set Up the Om UI

Having determined the module ID, we will use it ClojureScript, making a new def in our awesome-project.core:

(def swiper-type (js/require "react-native-swiper/dist/index"))

With this in place, it is easy to define a helper wrapper for use with Om:

(defn swiper [opts & children]
  (apply js/React.createElement
    swiper-type (clj->js opts) children))

We can then define our UI to match the example in the react-native-swiper README:

(def wrapper-style {})

(def slide-base-style
  {:flex           1
   :justifyContent "center"
   :alignItems     "center"})

(def slide1-style
  (assoc slide-base-style
    :backgroundColor "#9DD6EB"))

(def slide2-style
  (assoc slide-base-style
    :backgroundColor "#97CAE5"))

(def slide3-style
  (assoc slide-base-style
    :backgroundColor "#92BBD9"))

(def text-style
  {:color      "#fff"
   :fontSize   30
   :fontWeight "bold"})

(defn widget [data owner]
    (render [this]
      (swiper {:style wrapper-style}
        (view {:style slide1-style}
          (text {:style text-style}
            "Hello Swiper"))
        (view {:style slide2-style}
          (text {:style text-style}
        (view {:style slide3-style}
          (text {:style text-style}
            "And simple"))))))

That's all there is to it! The result:

For reference, the code is in this repo.

Hope this helps!

I'd like to thank the developers at Fy in helping me with this post—they are early adopters in building solutions using ClojureScript with React Native.

Tags: React Native iOS ClojureScript