Om
- Why another js framework
- Functional Reactive Programming
- Om = React + Clojurescript
Js framework recap
- Rapid development
- Routing for Single Page Applications
- Modular components
- Abstraction of dom interaction
Expertise required
<!-- Plain HTML -->
<h2 class="title">Foo</h2>
<p onclick="someFunc()">Bar</p>
<!-- AngularJS Templating -->
<span ng-class="variableInModel">example</span>
<div ng-show="anotherVariableInModel">hide or show me</div>
<custom-element>Custom</custom-element>
Problems
- Expertise required
- Performance
Problems
- Expertise required
- Performance
- Communication between components is difficult
Communication between components is difficult
- Encapsulation disrupts data bindings
$scope.emit('event', val)
$scope.broadcast('event', val)
$scope.on('event', function(val){
doSomethingWithVal
});
Problems
- Expertise required
- Performance
- Communication between components is difficult
- Hard to maintain large applications
- Long turn around time for business pivots
What do you do with state?
- Sharing state is hard
- Components are adaptable when isolated
- Leverage state
Functional Reactive Programming
- Comes from haskell community 1997
- Still evolving through research
- Declarative = Composable
What a behavior looks like
newtype Behavior a =
Behavior {
at :: Time -> a
}
myName :: Behavior Text
myName `at` yesterday
React
- Library (No more DOM manipulation)
- Focus on components
- Declarative
Om Improvements
- Immutable data structures
- No need for a templating language
- Cursors
- Communicating Sequential Processes
(def app-state (atom {:active 0
:tabs
[{:title "First" :class "dark-blue"
:view "First View"}
{:title "Second" :class "red"
:view "Second View"}
{:title "Third" :class "light-blue"
:view "Third View"}]}))
(defn tab-bar-view [view owner]
(dom/div #js {:className "tab-view"} view))
(defn tab [tab app index]
(let [className (str (:class tab)
" tab "
(if (= index (:active app)) "active" "" ))]
(dom/div #js {:onClick (fn [e] (om/update! app :active index))
:className className} (:title tab))))
(defn tab-bar-component [app owner]
(reify
om/IRender
(render [this]
(dom/div nil
(apply dom/div #js {:className "tab-bar"}
(map tab (:tabs app) (iterate identity app) (range)))
(om/build tab-bar-view (:view (nth (:tabs app) (:active app))))))))
(om/root
tab-bar-component
app-state
{:target (. js/document (getElementById "app"))})
Implications
- Interface builder
- Composable components
- Ability to scale to large apps
- Faster pivots