Top Related Projects
Quick Overview
Om is a library for building user interfaces with ClojureScript and React. It provides a powerful and flexible way to build complex, interactive web applications using the Clojure programming language.
Pros
- Functional Programming Approach: Om embraces the functional programming paradigm, which can lead to more maintainable and testable code.
- React Integration: Om is built on top of React, allowing developers to leverage the rich ecosystem and features of React.
- Performance: Om's efficient diffing algorithm and optimized rendering can lead to high-performance user interfaces.
- Immutable Data Structures: Om encourages the use of immutable data structures, which can simplify state management and improve overall application stability.
Cons
- Steep Learning Curve: Clojure and the functional programming paradigm can have a steeper learning curve compared to more traditional web development approaches.
- Limited Ecosystem: While Clojure and ClojureScript have a growing community, the ecosystem is smaller than that of more mainstream web development technologies.
- Tooling Maturity: The tooling and development environment for Clojure and ClojureScript may not be as mature as those for other popular web development languages.
- Interoperability Challenges: Integrating Om-based components with non-ClojureScript libraries or frameworks can sometimes be more challenging.
Code Examples
Here are a few code examples demonstrating the usage of Om:
- Rendering a Simple Component:
(require '[om.core :as om :include-macros true]
'[om.dom :as dom :include-macros true])
(defn hello-component [data owner]
(reify
om/IRender
(render [_]
(dom/div nil "Hello, " (om/get-shared owner :name) "!"))))
(om/root
hello-component
{:name "World"}
{:target (. js/document (getElementById "app"))
:shared {:name "World"}})
This code defines a simple Om component that displays a "Hello, World!" message.
- Handling User Interactions:
(defn counter-component [data owner]
(reify
om/IInitState
(init-state [_] {:count 0})
om/IRenderState
(render-state [_ state]
(dom/div nil
(dom/button
#js {:onClick #(om/update-state! owner :count inc)}
"Increment")
(dom/span nil (str "Count: " (:count state)))))))
(om/root
counter-component
{}
{:target (. js/document (getElementById "app"))})
This code creates a simple counter component that allows the user to increment a value.
- Communicating Between Components:
(defn parent-component [data owner]
(reify
om/IInitState
(init-state [_] {:message ""})
om/IRenderState
(render-state [_ state]
(dom/div nil
(dom/input
#js {:type "text"
:value (:message state)
:onChange #(om/set-state! owner :message (.. % -target -value))})
(om/build child-component (:message state))))))
(defn child-component [data owner]
(reify
om/IRender
(render [_]
(dom/div nil "Received message: " data))))
(om/root
parent-component
{}
{:target (. js/document (getElementById "app"))})
This code demonstrates how to communicate between a parent and child component in Om.
Getting Started
To get started with Om, you'll need to have Clojure and ClojureScript set up on your development environment. Here's a quick overview of the steps:
-
Install Leiningen, a popular Clojure build tool.
-
Create a new ClojureScript project using Leiningen:
lein new app my-om-app
-
Add Om as a dependency in your
project.clj
Competitor Comparisons
ClojureScript interface to Facebook's React
Pros of Om
- Simpler and more lightweight than Om Next
- Provides a more straightforward approach to building React-like applications
- Easier to learn and understand for beginners
Cons of Om
- Lacks some of the advanced features and flexibility of Om Next
- May not be suitable for larger, more complex applications
- Potentially less scalable than Om Next
Code Comparison
Om
(defui Counter
static om/IQuery
(query [this] [:count])
static om/IOmRecord
(initial-state [_] {:count 0})
Object
(render [this]
(let [{:keys [count]} (om/props this)]
(dom/div nil
(dom/button #js {:onClick #(om/update-state! this update :count inc)}
"Increment")
(dom/span nil (str "Count: " count))))))
(om/root
Counter
{:count 0}
{:target (. js/document (getElementById "app"))})
Om Next
(defui Counter
static om/IQuery
(query [this] [:count])
static om/IOmRecord
(initial-state [_] {:count 0})
Object
(render [this]
(let [{:keys [count]} (om/props this)]
(dom/div nil
(dom/button #js {:onClick #(om/transact! this `[(counter/increment {:count ~count})])}
"Increment")
(dom/span nil (str "Count: " count))))))
(def reconciler
(om/reconciler
{:state {:counter {:count 0}}
:parser (om/parser {:read read-counter :mutate mutate-counter})}))
(om/add-root! reconciler Counter (. js/document (getElementById "app")))
The main difference between the two examples is the use of Om Next's reconciler and transaction-based approach, which provides more flexibility and scalability for larger applications.
A ClojureScript framework for building user interfaces, leveraging React
Pros of re-frame
- Modular Design: re-frame encourages a modular and decoupled architecture, making it easier to manage and scale complex applications.
- Reactive Programming: re-frame's event-driven approach and reactive programming model can lead to more responsive and efficient applications.
- Comprehensive Documentation: re-frame has extensive documentation, providing clear guidance and best practices for building Clojure/ClojureScript applications.
Cons of re-frame
- Steeper Learning Curve: re-frame's architectural patterns and concepts may have a steeper learning curve compared to Om's simpler approach.
- Dependency on re-frame: re-frame is a core dependency for applications built with it, which can make it more difficult to migrate to other libraries or frameworks in the future.
- Verbosity: re-frame's event-driven architecture can sometimes lead to more boilerplate code compared to Om's more straightforward approach.
Code Comparison
Here's a brief comparison of a simple component in Om and re-frame:
Om:
(defui SimpleComponent
static om/IQuery
(query [this] [:text])
Object
(render [this]
(let [{:keys [text]} (om/props this)]
(dom/div nil text))))
(def simple-component (om/factory SimpleComponent))
re-frame:
(defn simple-component []
[:div (get @(re-frame/subscribe [:text]) 0)])
(re-frame/reg-sub
:text
(fn [db _]
(:text db)))
In the Om example, the component is defined using the defui
macro and the om/IQuery
protocol is used to specify the data dependencies. In the re-frame example, the component is a simple function that subscribes to the :text
subscription, which is defined separately.
Devcards aims to provide a visual REPL experience for ClojureScript
Pros of Devcards
- Devcards provides a powerful live development environment, allowing developers to quickly iterate and test their components in isolation.
- The library offers a rich set of features, including support for hot-reloading, interactive documentation, and visual regression testing.
- Devcards integrates well with other ClojureScript libraries, making it a versatile tool for building complex web applications.
Cons of Devcards
- Devcards has a steeper learning curve compared to Om, as it introduces additional concepts and configuration requirements.
- The library may be overkill for smaller projects or simple use cases, where the overhead of setting up Devcards may outweigh the benefits.
- Devcards is primarily focused on the development workflow and may not provide the same level of production-ready features as Om.
Code Comparison
Om:
(defui Counter
static om/IQuery
(query [this] [:count])
static om/IOmRecord
(initial-state [this] {:count 0})
Object
(render [this]
(let [{:keys [count]} (om/props this)]
(dom/div nil
(dom/button #js {:onClick #(om/update-state! this update-in [:count] inc)}
"Increment")
(dom/span nil (str "Count: " count))))))
(def counter (om/factory Counter))
Devcards:
(defcard-rg counter
(fn [data _]
(r/create-class
{:reagent-render
(fn []
[:div
[:button {:on-click #(swap! data update :count inc)}
"Increment"]
[:span "Count: " (:count @data)]])}))
{:count 0})
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Om
NOTE: This project is no longer under active development. If you'd like to use a library that's well maintained that was inspired by some of the ideas presented here see Fulcro
A ClojureScript UI framework and client/server architecture over Facebook's React.
Om UIs are out of the box snapshotable and undoable and these operations have no implementation complexity and little overhead.
Om borrows ideas liberally from Facebook's Relay and Netflix's Falcor with a dash of inspiration from Datomic pull syntax to avoid the typical incidental complexity that arises from client/server state management.
Dependency Information
Latest release: 1.0.0-beta1
Leiningen and Boot dependency information:
[org.omcljs/om "1.0.0-beta1"]
Maven dependency information:
<dependency>
<groupId>org.omcljs</groupId>
<artifactId>om</artifactId>
<version>1.0.0-beta1</version>
</dependency>
Example
(ns example
(:require [goog.dom :as gdom]
[om.dom :as dom]
[om.next :as om :refer [defui]]))
(defui Hello
Object
(render [this]
(dom/h1 nil "Hello, world!")))
(def hello (om/factory Hello))
(.render js/ReactDOM (hello) (gdom/getElement "example"))
Tutorials
There is an Quick Start tutorial that will introduce you to the core concepts of Om here. There are also a variety of other guides here.
Documentation
There is documentation here
Contributing
Please contact me via email to request an electronic Contributor Agreement. Once your electronic CA has been signed and returned to me I will accept pull requests.
Community
If you are looking for help please get in touch either on the clojurians.slack.com #om channel or the om-cljs Google Group.
References
- Worlds: Controlling the Scope of Side Effects
- A Functional I/O System
- Directness and Liveness in the Morphic User Interface Construction Environment
- Learnable Programming
- Relay
- Falcor
- GraphQL
- Datomic pull syntax
Copyright and license
Copyright © 2013-2017 David Nolen
Licensed under the EPL (see the file epl.html).
Top Related Projects
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot