-
Notifications
You must be signed in to change notification settings - Fork 364
Documentation
The Om life cycle protocols map more or less directly to the life cycle API present in Facebook's React.
Om component functions return reify
instances that implement the Om
life cycle protocols. When this
is used in a lifecycle protocol it refers
to the reify instance. As a rule of thumb it is not needed and can be discarded.
(defn my-widget [data owner]
(reify
om/IRender
(render [_]
(dom/h1 nil "Hello world!"))))
It's important to understand that my-widget
will be called many
times. Thus it's an anti-pattern to wrap reify
in a let
to
allocate stateful entities like core.async channels. Stateful entities
should be stored in component local state - om.core/IInitState
or
om.core/IWillMount
are good places to do this.
(defprotocol IInitState
(init-state [this]))
Called only once on an Om component. Implementations should return a map of initial state.
(defn my-widget [data owner]
(reify
om/IInitState
(init-state [_]
{:text "Hello world!"})
om/IRenderState
(render-state [_ state]
(dom/h1 nil (:text state)))))
(defprotocol IWillMount
(will-mount [this]))
Called once when the component is about to be mounted into the DOM. A useful place to establish persistent information and control like core.async channels and go loops.
(defprotocol IDidMount
(did-mount [this]))
Called once when the component has been mounted into the DOM. The DOM node associated with this component can be retrieved by using (om.core/get-node owner)
.
This is a good place to initialize persistent information and control that needs the DOM to be present.
(defprotocol IShouldUpdate
(should-update [this next-props next-state]))
You should only implement this if you really know what you're doing. Even then you probably shouldn't.
Implementations should return a boolean value. If true then the
component's om.core/IRender
or om.core/IRenderState
implementation
will be called. This provides the opportunity to prevent components
from re-rendering in response to certain changes in app (props) or local
state. Please note that preventing components from re-rendering
in response to props or state change could result in the DOM being out
of sync with application or local state.
next-props
is the next application state that the component is
associated with. next-state
is the next component local state, it is
always a map.
In your implementation if you wish to detect prop transitions you
must use om.core/get-props
to get the previous props. This is because your component
constructor function is called with the updated props.
(defprotocol IWillReceiveProps
(will-receive-props [this next-props]))
Not called on the first render, will be called on all subsequent renders. This is a good place to detect app state changes and make updates to local component state using om/set-state! or om/update-state!.
next-props
is the next application state associated with this
component.
In your implementation if you wish to detect prop transitions you
must use om.core/get-props
to get the previous props. This is
because your component constructor function is called with the
updated props.
(defprotocol IWillUpdate
(will-update [this next-props next-state]))
Not called on the first render, will be called on all subsequent renders. This is a good place to detect and act on state transitions.
next-props
is the next application state associated with this
component. next-state
is the next component local state, it is
always a map.
In your implementation if you wish to detect prop transitions you
must use om.core/get-props
to get the previous props. This is
because your component constructor function is called with the
updated props. Similarly, if you wish to detect local state transitions, you should use
om.core/get-render-state
to get the previous local state.
Note:: You cannot update local component state in this method. If you wish to change local state in response to prop changes use IWillReceiveProps.
(defprotocol IDidUpdate
(did-update [this prev-props prev-state]))
Called when React has rendered the component into the
DOM. prev-props
is the previous application state associated with
this component. prev-state
is the previous component local state, it
is always a map.
(defprotocol IRender
(render [this]))
Called on all changes to application state or component local state. Must return an Om component, a React component, or some value that React knows how to render.
If you implement om.core/IRender
you should not implement
om.core/IRenderState
.
(defprotocol IRenderState
(render-state [this state]))
The only difference between om.core/IRender
and
om.core/IRenderState
is that IRenderState
implementations get the
state as an argument. state
is always a map, you can use destructuring.
If you implement om.core/IRenderState
you should not implement
om.core/IRender
.
(defprotocol IDisplayName
(display-name [this]))
Return a string name to be used for debugging. The Chrome React Developer Tools extension uses this to name the components.
(defprotocol IWillUnmount
(will-unmount [this]))
Called immediately before a component is unmounted from the DOM.
Perform any necessary cleanup in this method, such as invalidating timers or cleaning up any DOM elements that were created in om.core/IDidMount
.
(defn get-props [owner]
...)
owner
is the backing Om component. om.core/get-props
returns the value associated with the component. This value is associated with the component by om.core/build
(and is referred to simply as x
in the documentation for build
). The value is usually a cursor, although any value is actually permitted. A cursor is a piece of the application state that knows how to update itself.
(defn get-state
([owner] ...)
([owner korks] ...))
owner
is the backing Om component. korks
is a key or sequence of
keys. Will return the specified piece of component local state. Will
always return pending state.
(defn get-shared
([owner] ...)
([owner korks] ...))
owner
is the backing Om component. korks
is a key or sequence of
keys. It will return data that is shared across the entire render tree.
You can set global shared data with om.core/root
.
(defn root
([f value options] ...))
f
is a function returning an instance of IRender
or IRenderState
.
f
takes two arguments, a root cursor on the application state and
the backing Om component for the root.
value
is either a tree of
associative ClojureScript data structures or an atom wrapping a tree
of associative ClojureScript data structures.
options
is a map containing any key allowed to om.core/build
.
Additionally the following keys are allowed/required:
-
:target
(required) -
:shared
(optional) in order to provide global services -
:tx-listen
a function that will listen in on transactions, should take 2 arguments:- a map containing the path, old and new state at path, old and new global state, and transaction tag if provided (
:path
,:old-value
,:new-value
,:old-state
,:new-state
and:tag
). - the root cursor.
- a map containing the path, old and new state at path, old and new global state, and transaction tag if provided (
-
:path
to specify the path of the cursor into app-state (see #72) -
:instrument
a function of three arguments that if provided will intercept all calls toom.core/build
. The function arguments correspond exactly to the three argument arity ofom.core/build
om.core/root
is idempotent. You may safely call it multiple
times. Only one Om render loop is ever allowed on a particular DOM
target.
(om.core/root
(fn [app-state owner]
(reify
om.core/IRender
(render [_]
(dom/h1 nil (:text app-state)))))
{:text "Hello world!"}
{:target (. js/document getElementById "my-app")})
(defn build
([f x] ...)
([f x m] ...))
Constructs an Om component. f
must be a function that returns an
instance of om.core/IRender
or om.core/IRenderState
. f
must take
two arguments - a value and the backing Om component usually referred
to as the owner. f
can take a third argument if :opts
is specified
in m
. The component is identified by the function f
. Changing f
to a different function will construct a new component, while changing
the return value will not change component. x
can be any value. m
is an optional map of options.
Only the following keys are allowed in m
.
:key
- a keyword that will be used to lookup a value in x
to
be used as a React key.
:key-fn
- a function that will be applied to x
to be used as a
React key.
:react-key
- a value to use as a React key.
:fn
- a function to apply to x
before invoking f
.
:init-state
- a map of initial state to set on the component (state from IInitState
is merged onto it).
:state
- a map of state to merge into the component.
:opts
- a map of side information.
(defn build*
([f x] ...)
([f x m] ...))
Identical to om.core/build
except cannot be intercepted by the
:instrument
argument provided to om.core/root
. Needed to avoid
infinite loops in components constructed via :instrument
.
(defn build-all
([f xs] ...)
([f xs m] ...)
Conceptually the same as om.core/build
, the only difference is that
it returns a sequence of Om components. xs
is a sequence of
values. f
and m
are the same as om.core/build
. To avoid
the warning "Each child in an array should have a unique “key” prop",
add either a :key
or :key-fn
to m
.
(defn transact!
([cursor f] ...)
([cursor korks f] ...)
([cursor korks f tag]) ...)
The primary way to transition application state. cursor
is an Om
cursor into the application state. f
is a function that will receive
the specified piece of application state. korks
is an optional
key or sequence of keys to access in the cursor. tag
is optional
information to tag the transaction. tag
should be either a keyword
or a vector whose first element is a keyword
.
(transact! cursor :text (fn [_] "Changed this!"))
(defn update!
([cursor v] ...)
([cursor korks v] ...)
([cursor korks v tag] ...))
Similar to om.core/transact!
but just sets a cursor to a new value,
analagous to reset!
for atoms.
(update! cursor [:text] "Changed this!")
(defn path
([cursor] ...))
(defn state
([cursor] ...))
(defn value
([cursor] ...))
(defn get-node
([owner ref] ...)
([owner] ...))
owner
is the backing Om component. ref
is a JavaScript String that
references a DOM node. This functionality is identical to the
ReactComponent.getDOMNode
in React.
(defn set-state!
([owner v] ...)
([owner korks v] ...))
Sets component local state. owner
is the backing Om
component. korks
is an optional key or sequence of keys. v
is the value to
set. Will trigger an Om re-render.
(defn update-state!
([owner f] ...)
([owner korks f] ...))
Takes a pure owning component, an optional sequential list of keys and a function to transition the state of the component. Conceptually analogous to React setState
. Will schedule an Om re-render.
(defn refresh! [owner]
...)
Utility to re-render an owner. Delegates to update-state!
.
(defn get-render-state
([owner] ...)
([owner korks] ...))
Returns rendered component local state. owner
is the backing Om
component. korks
is an optional key or sequences of keys. Similar to
om.core/get-state
except always returns the rendered state. Useful
for detecting state transitions.
(defn detach-root [target]
...)
Given a DOM target, remove its render loop if one exists.
(defn root-cursor [atom]
...)
Given an application state atom, return a root cursor for it.
(defn ref-cursor [cursor]
...)
Given a cursor, return a reference cursor that inherits all of the
properties and methods of the cursor. Reference cursors may be
observed via om.core/observe
.
(defn observe [owner ref]
...)
Given a component and a reference cursor, have the component observe the reference cursor for any data changes. Evaluates to the given reference cursor.
(defmacro component [& body]
...)
Sugar over reify
for quickly putting together components that
only need to implement om.core/IRender
and don't need access to
the owner argument.
The dom functions map directly to the DOM api presented by React. For
example React.DOM.div
becomes om.dom/div
. The arguments are exactly
the same as React, the first argument is props
, all subsequent
arguments are children
.
For a list of supported props
see React's supported DOM attributes and React's special attributes. As an example of the special attributes, the following code will create a div
component that contains raw HTML:
(om.dom/div #js {:dangerouslySetInnerHTML #js {:__html "<b>Bold!</b>"}}
nil)
Be careful! The attribute is well-named: this is potentially dangerous and should be used with caution.
(defn render-to-str [c]
...)
Equivalent to React.renderComponentToString
. For example:
(dom/render-to-str (om/build some-widget data))