How to use StackNavigator of React Navigation in clojurescript - react-native

I am new to clojurescript and reagent. I try to use react-navigation in my react-native app but I getting this error
Error rendering component (in env.main.reloader > exp_cljs.core.app_root > reagent2)
This is my code
(def react-navigation (js/require "react-navigation"))
(def StackNavigator (aget react-navigation "StackNavigator"))
(defn Home
[]
[text "Hello Navigator"])
(defn SimpleApp
[]
(StackNavigator
(clj->js {:Home {:screen (r/create-class {:reagent-render (Home)})}})))
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent rn/app-registry "main" #(r/reactify-component app-root)))
This is my app-root
(defn app-root []
(SimpleApp)); -- error
;(r/create-class {:reagent-render SimpleApp}); error
;(r/as-element (SimpleApp)); -- error
;(r/adapt-react-class SimpleApp)); -- error

(ns same.app
(:require [reagent.core :as r]
[same.ui :as ui]
[same.util :as u]
[same.screens.auth :refer [AuthScreen]]
; [same.screens.reg :refer [RegScreen]]
; [same.screens.resend :refer [ResendScreen]]
[same.screens.splash :refer [SplashScreen]]
; [same.screens.drawer :refer [Drawer]]
[same.screens.presentation :refer [Presentation]]))
(def routes #js {;:Drawer #js {:screen (r/reactify-component Drawer)}
:AuthScreen #js {:screen (r/reactify-component AuthScreen)}
;:RegScreen #js {:screen (r/reactify-component RegScreen)}
;:ResendScreen #js {:screen (r/reactify-component ResendScreen)}
:Presentation #js {:screen (r/reactify-component Presentation)}
:Splash #js {:screen (r/reactify-component SplashScreen)}})
(def Routing (ui/StackNavigator.
routes
#js {:initialRouteName "Splash"
:headerMode "none"
:mode "modal"}))
(def routing (r/adapt-react-class Routing))
(defn AppNavigator []
(fn []
[routing]))
and android.core:
(ns same.android.core
(:require [reagent.core :as r :refer [atom]]
[re-frame.core :refer [dispatch-sync]]
[same.ui :as ui]
[same.events]
[same.subs]
[same.app :refer [AppNavigator]]))
(aset js/console "disableYellowBox" true)
(defn app-root []
(fn []
[AppNavigator]))
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent ui/app-registry "Same" #(r/reactify-component app-root)))

The trick is to convert React Native components to Reagent components and back where needed. In the following example definitions of login-screen and main-screen are omitted, they're just regular Reagent components.
(def react-navigation (js/require "react-navigation"))
(def stack-navigator (.-createStackNavigator react-navigation))
(def switch-navigator (.-createSwitchNavigator react-navigation))
; ...
; ...
; ...
(defn application-nav-stack []
(stack-navigator (clj->js { "MainApp" (r/reactify-component main-screen) })))
(defn authentication-nav-stack []
(stack-navigator (clj->js { "Login" (r/reactify-component login-screen) })))
(defn app-navigation-switch []
(switch-navigator
(clj->js { :Auth (authentication-nav-stack) :MainApp (application-nav-stack) })
(clj->js { :initialRouteName :Auth } )))
(defn app-root []
[ (r/adapt-react-class (app-navigation-switch)) ] )
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent app-registry "MyApp" #(r/reactify-component app-root)))
Whenever you pass a Reagent component to ReactNavigation function you need to use reactify-component to convert it to the native JS form; whenever you need to use ReactNavigation component as a part of Reagent component, you need to use adapt-react-class to convert it back.

Related

Using ReactNative External library in ClojureScript Project - Syntax

I am trying to use react-native-swipe-list-view inside clojurescript. But I am having some trouble in converting documented js code in cljs code.
Documentations:
import { SwipeRow } from 'react-native-swipe-list-view';
<SwipeRow>
<View>
</View>
</SwipeRow>
My Cljs Code:
(:require [react-native-swipe-list-view :as swipe_list])
(defn item[]
(
[swipe_list/SwipeRow
[:View]]
))
Online tool:
(def SwipeRow (.-SwipeRow (js/require "react-native-swipe-list-view")))
(defn item[]
(
[SwipeRow
[:View]]
))
None of the above worked. I am new to cljs. it will be a big help if someone can tell me how to convert the above lines of js into cljs. Thanks
Reagent Documents: Creating Reagent "Components" from React Components
Here I am going to create two reagent components, view and swipeRow. I am using different ways for both, to show two ways for importing library and creating components. You can use either.
;; Importing Reagent and React Native
(ns type_name_server_here
(:require [reagent.core :as reagent]
["react-native" :as rn]))
;; 1st Way: Importing SwipeRow
(def SwipeRowImport (.-SwipeRow (js/require "react-native-swipe-list-view")))
;; Converting it into Reagent Component
(def SwipeRow (reagent/adapt-react-class SwipeRowImport))
;; 2nd Way: Importing View from already imported react-native library and converting it into reagent component
(def view (reagent/adapt-react-class (.-View ^js rn)))
;; SwipeRow requires two children (Check out documentation)
(defn item[]
(
[SwipeRow
[view] [view]]
))
If you are using shadow-cljs, you can use this table as a reference, for converting ES6 Import statments to CLJS Require

How to use react navigation in cljs?

Here’s my code in which I’m trying to create multiple bottom tabs using react navigation
(defn sample-comp []
[:> View [:> Text "Sample Container!"]])
(defn root-comp []
[:> NavigationContainer
[:> SafeAreaView
(let [Tab (createBottomTabNavigator)]
[:> (.-Navigator Tab)
[:> (.-Screen Tab)
{:name "Home"
:component (r/reactify-component sample-comp)}]])]])
(defn init []
;; register error also occurs if there's a non-
;; related error in the code
(dispatch [:register-db])
(render-root "Humboi" (r/as-element [root-comp])))
but I’m getting the following error:
requireNativeComponent: “RNCSafeAreaProvider” was not found in UIManager.
How to fix this error?

How to properly import components from other files using reagent?

I want to use a reagent component I've created in another file/namespace, say this.is.the.namespace, and it contains a component defined like so:
(defn component-name []
; stuff
)
In my entry file, I do the following:
(ns entry.point.namespace.name
(:require [this.is.the.namespace]
))
And when I include [component-name] in a component in the entry file, the component doesn't show. Why might this be?
(ns this.is.the.namespace)
(defn component-name []
[:p "Hello There"])
(ns entry.point.namespace.name
(:require [reagent.core :as reagent]
[this.is.the.namespace :as my-components]))
(reagent/render [my-components/component-name] (js/getElementById "main-div"))
Change "main-div" to id of the div that you are rendering into.

Using react-native-camera in ClojureScript re-natal development

Has anyone used 'react-native-camera' component with re-natal?
I am just trying out the react-native-camera component in the default re-natal skeleton project.
My code is following
(ns wmshandheld.android.core
(:require [reagent.core :as r :refer [atom]]
[re-frame.core :refer [subscribe dispatch dispatch-sync]]
[wmshandheld.events]
[wmshandheld.subs]))
(def ReactNative (js/require "react-native"))
(def ReactNativeCamera (js/require "react-native-camera"))
(def app-registry (.-AppRegistry ReactNative))
(def camera (.-Camera ReactNativeCamera))
(def text (r/adapt-react-class (.-Text ReactNative)))
(def view (r/adapt-react-class (.-View ReactNative)))
(def touchable-highlight (r/adapt-react-class (.-TouchableHighlight ReactNative)))
(defn alert [title]
(.alert (.-Alert ReactNative) title))
(defn app-root []
(fn []
[view {:style {:flex-direction "column" :margin 40 :align-items "center"}}
[camera {:ref (fn [cam]
(this-as this
(set! (.-camera this) cam)))
:style {:flex 1 :justify-content "flex-end" :align-items "center"}
:aspect (.-fill (.-Aspect (.-constants camera)))}
[text {:style {:flex 0 :background-color "#fff"
:border-radius 5 :color "#000"
:padding 10 :margin 40}
:on-press #(alert "HELLO!")}
"[CAPTURE]"]]]))
(defn init []
(dispatch-sync [:initialize-db])
(.registerComponent app-registry "WMSHandheld" #(r/reactify-component app-root)))
But I got such an error.
console.error: "Error rendering component (in wmshandheld.android.core.app_root)"
error
YellowBox.js:71:16
finishClassComponent
ReactNativeFiber-dev.js:1667:86
updateClassComponent
ReactNativeFiber-dev.js:1659:33
beginWork
ReactNativeFiber-dev.js:1786:44
performUnitOfWork
ReactNativeFiber-dev.js:2528:33
workLoop
ReactNativeFiber-dev.js:2554:141
_invokeGuardedCallback
ReactNativeFiber-dev.js:73:23
invokeGuardedCallback
ReactNativeFiber-dev.js:47:40
performWork
ReactNativeFiber-dev.js:2593:41
scheduleUpdateImpl
ReactNativeFiber-dev.js:2728:101
scheduleUpdate
ReactNativeFiber-dev.js:2711:38
enqueueSetState
ReactNativeFiber-dev.js:1514:90
setState
react.development.js:218:31
<unknown>
figwheel-bridge.js:88:33
waitForFinalEval
figwheel-bridge.js:197:21
<unknown>
figwheel-bridge.js:28:17
fireEvalListenters
figwheel-bridge.js:27:41
<unknown>
figwheel-bridge.js:118:24
tryCallOne
core.js:37:14
<unknown>
core.js:123:25
<unknown>
JSTimers.js:301:23
_callTimer
JSTimers.js:154:6
_callImmediatesPass
JSTimers.js:202:17
callImmediates
JSTimers.js:470:11
__callImmediates
MessageQueue.js:278:4
<unknown>
MessageQueue.js:145:6
__guard
MessageQueue.js:265:6
flushedQueue
MessageQueue.js:144:17
callFunctionReturnFlushedQueue
MessageQueue.js:119:11
Does anyone know what is the problem? and how to solve it? just a bare working example that uses react-native-camera on github or gist would be perfect!...
If this helps this is how I can atleast get the camera to display in the emulator. I havent pasted the whole code but by using [view [camera-component]] in the app root the emulator shows the back camera component. Hope this helps
(def ReactNativeCamera (js/require "react-native-camera"))
(def camera (r/adapt-react-class (.-RNCamera ReactNativeCamera)))
(defn camera-component
[]
(let data {}]
(fn []
[view
[text "hello"]
[camera {
:ref (fn [cam] (this-as this (set! (.-Camera this) cam)))
:style {:flex 1 :justify-content "flex-end" :align-items "center" :border-color "black" :border-width 1 :min-height "10%"}
:type (-> ReactNativeCamera .-RNCamera .-Constants .-Type .-back)
:permission-dialog-title "Permission to use camera"
:permission-dialog-message "Need permission to use camera on your phone"}]])))

How can I compile code ClojureScript for use in PhantomJS?

I'm trying to script PhantomJS in ClojureScript. I'm targeting Node and using phantomjs-node [1]. I have a basic example working:
(def phantom (js/require "phantom"))
(defn -main [& args]
(-> phantom
(.create (fn [browser]
(-> browser
(.createPage (fn [page]
(-> page
(.open "http://google.com" (fn [status]
(if (= status "success")
(-> page (.render "example.png")))
(-> browser .exit)))))))))))
Now, if I use evaluate function [2] of PhantomJS webpage object, I the following error:
phantom stdout: ReferenceError: Can't find variable: <namespace here>
When compiling into JavaScript the code to be evaluated contains the CLJS namespace and hence doesn't properly eval within the context of PhantomJS' webpage object. Here is an example:
(defn -main [& args]
(-> phantom
(.create (fn [browser]
(-> browser
(.createPage (fn [page]
(-> page
(.open "http://google.com" (fn [status]
(println (str "opened google? " status))
(-> page
(.evaluate #(-> document .-title)
#(do
(println (str "Page title is " %))
(-> browser .exit))))))))))))))
How can I prevent the code to be evaluated within the webpage object of PhantomJS from being namespaced with the CLJS namespace? Or secondly do I have any other options?
[1] https://github.com/sgentle/phantomjs-node
[2] http://phantomjs.org/api/webpage/method/evaluate.html
You need to use js/document instead of document.
document is a reference to clojurescript variable, js/document is a document in js world.