working solution with om-next stateful components

- added re-natal.support namespace which provides functions to make it possible mounting om root application not on "real" root node but on other component which acts as a root node.
This commit is contained in:
Artur Girenko 2016-02-10 22:14:05 +01:00
parent 30b371c591
commit ca43c940fb
4 changed files with 87 additions and 22 deletions

View File

@ -37,6 +37,7 @@ interfaceConf =
ios: ["core.cljs"]
android: ["core.cljs"]
common: ["handlers.cljs", "subs.cljs", "db.cljs"]
other: []
deps: ['[reagent "0.5.1" :exclusions [cljsjs/react]]'
'[re-frame "0.6.0"]'
'[prismatic/schema "1.0.4"]']
@ -48,10 +49,11 @@ interfaceConf =
ios: ["core.cljs"]
android: ["core.cljs"]
common: []
other: [["support.cljs","re_natal/support.cljs"]]
deps: ['[org.omcljs/om "1.0.0-alpha28" :exclusions [cljsjs/react cljsjs/react-dom]]'
'[natal-shell "0.1.6"]']
shims: ["cljsjs.react", "cljsjs.react.dom"]
sampleCommand: '(swap! app-state assoc :app/msg "Hello Native World")'
sampleCommand: '(swap! app-state assoc :app/msg "Hello Native World!")'
interfaceNames = Object.keys interfaceConf
log = (s, color = 'green') ->
@ -257,6 +259,7 @@ shimCljsNamespace = (ns) ->
copySrcFiles = (interfaceName, projName, projNameUs, projNameHyph) ->
cljsDir = interfaceConf[interfaceName].cljsDir
fileNames = interfaceConf[interfaceName].sources.common;
for fileName in fileNames
path = "src/#{projNameUs}/#{fileName}"
@ -272,6 +275,12 @@ copySrcFiles = (interfaceName, projName, projNameUs, projNameHyph) ->
fs.copySync("#{resources}/#{cljsDir}/#{fileName}", path)
edit path, [[projNameHyphRx, projNameHyph], [projNameRx, projName], [platformRx, platform]]
otherFiles = interfaceConf[interfaceName].sources.other;
for cpFile in otherFiles
from = "#{resources}/#{cljsDir}/#{cpFile[0]}"
to = "src/#{cpFile[1]}"
fs.copySync(from, to)
shims = fileNames = interfaceConf[interfaceName].shims;
for namespace in shims
shimCljsNamespace(namespace)

View File

@ -1,25 +1,52 @@
(ns $PROJECT_NAME_HYPHENATED$.$PLATFORM$.core
(:require-macros [natal-shell.components :refer [view text image touchable-highlight]]
[natal-shell.alert :refer [alert]])
(:require [om.next :as om :refer-macros [defui]]))
(:require [om.next :as om :refer-macros [defui]]
[re-natal.support :as sup]))
(set! js/React (js/require "react-native"))
(def app-registry (.-AppRegistry js/React))
(def logo-img (js/require "./images/cljs.png"))
(defonce app-state (atom {:app/msg "Hello Clojure in iOS and Android!"}))
(defui AppRoot
static om/IQuery
(query [this]
'[:app/msg])
Object
(render [this]
(view {:style {:flexDirection "column" :margin 40 :alignItems "center"}}
(text {:style {:fontSize 30 :fontWeight "100" :marginBottom 20 :textAlign "center"}} "Hello World!")
(image {:source logo-img
:style {:width 80 :height 80 :marginBottom 30}})
(touchable-highlight {:style {:backgroundColor "#999" :padding 10 :borderRadius 5}
:onPress #(alert "HELLO!")}
(text {:style {:color "white" :textAlign "center" :fontWeight "bold"}} "press me")))))
(.log js/console "rendering app")
(let [{:keys [app/msg]} (om/props this)]
(view {:style {:flexDirection "column" :margin 40 :alignItems "center"}}
(text {:style {:fontSize 30 :fontWeight "100" :marginBottom 20 :textAlign "center"}} msg)
(image {:source logo-img
:style {:width 80 :height 80 :marginBottom 30}})
(touchable-highlight {:style {:backgroundColor "#999" :padding 10 :borderRadius 5}
:onPress #(alert "HELLO!")}
(text {:style {:color "white" :textAlign "center" :fontWeight "bold"}} "press me"))))))
(def app-root (om/factory AppRoot))
(defmulti read om/dispatch)
(defmethod read :default
[{:keys [state]} k _]
(let [st @state]
(if-let [[_ v] (find st k)]
{:value v}
{:value :not-found})))
(defonce reconciler
(om/reconciler
{:state app-state
:parser (om/parser {:read read})
:root-render sup/root-render
:root-unmount sup/root-unmount}))
(defonce RootNode (sup/root-node 1))
(defonce app-root (om/factory RootNode))
(defn init []
(.registerComponent app-registry "ReagentApp" #(app-root)))
(om/add-root! reconciler AppRoot 1)
(.registerComponent app-registry "$PROJECT_NAME$" (fn [] app-root)))

View File

@ -1,21 +1,15 @@
(ns ^:figwheel-no-load env.$PLATFORM$.main
(:require [om.next :as om :refer-macros [defui]]
(:require [om.next :as om]
[$PROJECT_NAME_HYPHENATED$.$PLATFORM$.core :as core]
[figwheel.client :as figwheel :include-macros true]))
(enable-console-print!)
(defui Reloader
Object
(render [_] (core/app-root)))
(def reloader (om/factory Reloader))
(def root-el (reloader))
(figwheel/watch-and-reload
:websocket-url "ws://localhost:3449/figwheel-ws"
:heads-up-display true
;; :jsload-callback #(.forceUpdate Reloader)
)
:jsload-callback #(om/add-root! core/reconciler core/AppRoot 1))
(core/init)
(core/init)
(def root-el (core/app-root))

View File

@ -0,0 +1,35 @@
(ns re-natal.support
(:require [om.next :refer-macros [ui]]))
(def root-nodes (atom {}))
(defn root-node
"A substitute for a real root node (1) for mounting om-next component.
You have to call function :on-render and :on-unmount in reconciler :root-render :root-unmount function."
[id]
(let [content (atom nil)
instance (atom nil)
class (ui Object
(componentWillMount [this] (reset! instance this))
(render [_] @content))]
(swap! root-nodes assoc id {:on-render (fn [el]
(reset! content el)
(when @instance
(.forceUpdate @instance)))
:on-unmount (fn [])
:class class})
class))
(defn root-render
"Use this as reconciler :root-render function."
[el id]
(let [node (get @root-nodes id)
on-render (:on-render node)]
(when on-render (on-render el))))
(defn root-unmount
"Use this as reconciler :root-unmount function."
[id]
(let [node (get @root-nodes id)
unmount-fn (:on-unmount node)]
(when unmount-fn (unmount-fn))))