Skip to content

Documentation (om.next)

Daniel Stockton edited this page Jul 7, 2017 · 99 revisions

WARNING: This page documents alpha software.

Table of Contents

om.dom

om.next

om.dom

node

(dom/node some-component)

Return the DOM node associated with a component.

render-to-str

(defn render-to-str [c]
  ...)

Equivalent to React.renderComponentToString. For example:

(dom/render-to-str (om/build some-widget data))

om.next

Macros

defui

(defui MyComponent
  Object
  (componentDidMount [this]
                     (.log js/console "did mount"))
  (render [this]
          (div nil "Hello, world!")))

Macro for defining components. defui creates a JavaScript class that inherits from React.Component. defui is like deftype but there is no support for defining fields. In addition there is special handling of the "static" protocols om.next/Ident, om.next/IQuery and om.next/IQueryParams. The React component specs and lifecycle methods are available at the react docs.

ui

(ui
  Object
  (componentDidMount [this]
                     (.log js/console "did mount"))
  (render [this]
          (div nil "Hello, world!")))

Macro for defining anonymous components. Similar to defui with the exception that it doesn't take the component's name.

Query & Identity

Ident

(defui MyComponent
  static om/Ident
  (ident [this props]
    [:some/key (:some/id props)])

A protocol for identity resolution. This protocol is used to solve two problems. First, in the case where initial state or state novelty is supplied in a denormalized form. Second, when making an association from a logical entity to multiple component instances. The first case simplifies the problem of updating data while the latter simplifies keeping multiple views of the same data in sync.

IQuery

(defui MyComponent
  static om/IQuery
  (query [this]
    [:prop-a :prop-b])
  Object
  (render [this]
    (div nil "Hello, world!")))

A protocol for declaring queries. This method should always return a vector. The query may include quoted symbols that start with ?. If bindings for these query variables are supplied via IQueryParams they will replace the symbols.

IQueryParams

(defui MyComponent
  static om/IQueryParams
  (params [this]
    {:start 0 :end 10})
  static om/IQuery
  (query [this]
    '[(:list/items {:start ?start :end ?end})])
  Object
  (render [this]
    (div nil "Hello, world!")))

Define params to bind to the query. Should be a map of keywords that match query variables present in the query.

get-query

(om.next/get-query MyComponent)

Returns the bound query for the component.

get-unbound-query

(om.next/get-unbound-query MyComponent)

Returns the query for the component before parameter binding.

get-params

(om.next/get-params x)

Return the current query parameters for a component.

set-query!

(om.next/set-query! some-component {:query [:foo :baz]})

Change the query of a component. Takes a map containing :params and/or :query. :params should be a map of new bindings and :query should be a query expression. Will schedule a re-render as well as remote re-sends if necessary.

update-query!

(om/update-query! some-component
                  (fn [{:keys [query params] :as q}]
                    (update q :query conj :foo)))

Update a component's query and/or query parameters with a function.

query->ast

(om.next/query->ast '[(:foo {:bar 1})])

Given a query expression return the AST.

ast->query

(om.next/ast->query ast)

Given a query expression AST, unparse it into a query expression.

focus-query

(om.next/focus-query [{:foo [:bar :baz]} :woz] [:foo :bar])
;; => [{:foo [:bar]}]

Given a query, focus it along the specified path.

Components

factory

(om.next/factory MyComponent
  {:keyfn :id :validator my-validator})

Create a factory function from an Om component. Can optionally supply :keyfn - this should produce the React key property from the component props. Can also supply :validator, a function which should assert that the props are valid.

component?

(om.next/component? 1) ;; false

Returns true if the argument is a component.

react-key

(om.next/react-key some-component)

Returns the React key.

react-type

(om.next/react-type some-component)

Returns the component constructor. Works even if the component has not been mounted.

props

(defui MyComponent
  Object
  (render [this]
    (let [{:keys [foo bar]} (om/props this)]
      ;; ...
      )))

Get the immutable props for an Om component.

computed

(some-widget
  (om/computed props
    {:delete (fn [e] ...)
     :update (fn [e] ...)}))

Add computed information to props. Useful for passing down computed information like event handling callbacks and client only (non-remote) state. The first argument should be props, the second argument a map. Note that calling computed will replace any pre-existing computed properties.

get-computed

(let [{:keys [delete update]} (om/get-computed this)]
  ...)

Return the computed properties on props. The first argument can be props or a component. The second argument can be a keyword or sequential collection of keys for deeply accessing the computed properties.

children

(defui MyComponent
  Object
  (render [this]
    (let [children (om/children this)]
      children)))

Pass through child components/nodes as trailing arguments after props. Can be used to e.g. pass the body through to a modal component.

get-ident

(om.next/get-ident some-component)

Given a component, return its ident

set-state!

(om.next/set-state! some-component {:foo :bar})

Set component local state. Will schedule the component for re-render.

react-set-state!

(om.next/react-set-state! some-component {:foo :bar})
(om.next/react-set-state! some-component {:foo :bar} #(println "some-callback"))

Perform a stock react setState! outside of the om.next "render loop". Useful for preventing state changes from interrupting animations.

update-state!

(om.next/update-state! some-component update :some/key inc)

Update a component's local state. Similar to Clojure(Script)'s swap!.

get-state

(om.next/get-state some-component)

Return the component local state. Will be the latest state, not the rendered component state.

get-rendered-state

(om.next/get-rendered-state some-component)

Return the rendered component local state.

mounted?

(om.next/mounted? some-component)

Returns true if the component is mounted.

react-ref

(om.next/react-ref some-component :foo/widget)

Return a component associated with the supplied name - can be a keyword or string.

subquery

(om.next/subquery x subquery-ref subquery-class)

Once a component has mounted it may wish to use a instantiated child as the source of the subquery. subquery will return the query provided by the component associated with subquery-ref when mounted. Otherwise it will fallback on the query provided statically by subquery-class.

Parsing & Mutations

parser

(om.next/parser {:read read-fn :mutate mutate-fn})

Construct a parser from the supplied configuration map. The map should only have two keys:

  • :read - a function of three arguments [env key params] that should return a valid parse result map. This map can contain a :value entry along with remote entries. If :value is supplied it will be used to rewrite a value in the resulting tree. Remote query entries must be query expression AST fragments that correspond to the :remotes specified to the reconciler.
  • :mutate - a function of three arguments [env key params] that should return a valid parse mutation result map. This map should contain a :value and an :action entry. :value is an optional hint at keys affected by the mutation; it has no effect on rerendering and should only contain keys valid for :read functions. The value of :action should be a function of zero arguments that applies the requested mutation.

Returns a function of up to three arguments. The first argument should be the env map. The second argument should be the query expression. The final optional argument sets the parse mode to remote, defaults to false.

dispatch

A helper function for writing read and mutate multimethods that dispatch on key.

(defmulti mutate om/dispatch)

(defmethod mutate `do/something ...)

transact!

(om.next/transact! some-component
  `[(todo/update `{:title "Get Milk!"})
    :todos/list :todos/else])

Transition the application state. transact! takes two arguments. The first argument may be either a component instance or a reconciler. If it is a component, Om will implicitly update it based on its query after the transaction. The second argument is a query expression that includes mutation. The query expression should contain any additional keys which should be re-read following the mutations (e.g. :todos/list). These reads will schedule components which depend on the specified keys to re-render. Returns a map from mutation function symbols to maps including :query and :result entries, where result is the new application state after the application of the corresponding mutation function.

force

(om.next/transact! some-component
  `[(do/it!) ~(force :foo :custom-remote)])

Attempt to force a read from some specific remote. During parsing this is detectable by the presence of an explicit :target entry on the query AST.

Indexing

ref->components

(om.next/ref->components reconciler [todo/by-id 0])

A development time helper. Given a reference return all the components that match. The reference can be a keyword or an ident. If keyword will return all components with the given property.

ref->any

(om.next/ref->any reconciler [todo/by-id 0])

A development time helper. Given a reference return the first component that matches. The reference can be a keyword or an ident. If keyword will return any component with the given property.

class->any

(om.next/class->any reconciler SomeClass)

A development time helper. Given a class return a matching component. To find the component it will have to have been added to the reconciler via add-root!.

full-query

(om.next/full-query Component)

Returns the absolute query for a given component, not relative like om.next/get-query.

Normalization / Denormalization (Default Database)

The following operations are only needed if you intend to leverage the default database format. If you are using a custom client side in-memory database like DataScript, the following operations are unnecessary.

tree->db

(om.next/tree->db SomeComponent some-data)

Given a component (or query expression) and some data, normalize the data into the default database format according to the query. All nodes that can be mapped via Ident implementations will be replaced with the ident as link. The original node data will be merged into tables indexed by ident.

Can pass optional third argument to merge the ident indexed tables back into the result. Otherwise must be accessed via meta on the result.

db->tree

(om.next/db->tree query some-data app-state-db)

Given a query expression, some data in the default database format, some application state data in the default database format, denormalize it. This will replace all ident link nodes with their actual data recursively. This is useful in parse in order to avoid manually joining in nested relationships.

Reconciler

reconciler

(om.next/reconciler
  {:state app-state
   :parser my-parser})

Construct a reconciler based on the supplied configuration. The configuration can be a map with the following keys:

  • :state - the application state. If not an atom the reconciler will normalize the data with the query supplied by the root component.
  • :parser - a parser
  • :normalize - whether to normalize the data provided by the user. If reconciler is given IAtom for :state this defaults to false.
  • :remotes - a vector logical remotes present in the system. Remotes are simply user specified keywords. If not specified, a default remote :remote will be made available.
  • :send - a function of two arguments. The first argument will be a map of remotes and the pending message to be sent. The second argument is a callback that can be invoked as many times as necessary with the results from the various remotes. It's up to the user to specify the remote resolution order and whether data will be loaded piecemeal or all at once. This callback is multi-arity. With one argument, pass the novelty. With two arguments, pass the novelty as the first argument, and then pass a query as the second argument. The latter is useful for more custom merge implementations. (See :merge below.)
  • :root-render - the root render function. Defaults to ReactDOM.render. Can be switched out according to context, i.e. React Native.
  • :root-unmount - the root unmount function. Defaults to ReactDOM.unmountComponentAtNode. Can be switched out according to context, i.e. React Native.
  • :shared - a map of arbitrary values to be shared across all components, accessible to them via (om/shared this). Comparable to om.now's om/get-shared
  • :shared-fn - a function to compute global shared properties from the root props. The result is merged with :shared
  • :merge - a function of four arguments: reconciler, state, novelty, query. This is the mechanism by which both the merge! function, and the callback passed into the reconciler's :send function, merge novelty back into app state. The default value for this is default-merge. Must return a map containing the following keys: :keys, :next. :keys is a vector of keys in app state that have been affected by the merge. :next is the next app-state. Optionally, :tempids can be added for resolving tempids into stable ids.
  • :logger - supply a goog.log compatible logger. Set to nil if you want to disable logging.

reconciler?

(om.next/reconciler? x)

Returns true if the argument is a reconciler instance, false otherwise.

get-reconciler

(om.next/get-reconciler some-component)

Returns the reconciler that some-component belongs to.

add-root!

(om.next/add-root! reconciler
  MyRootComponent (goog.dom/getElement "app"))

Add a DOM root for the reconciler to control. The first argument is a reconciler, the second a root component, and the last, a DOM node target.

remove-root!

(om.next/remove-root! reconciler (goog.dom/getElement "app"))

Given a reconciler and DOM target node, remove the DOM target from the reconciler's control.

merge!

(om.next/merge! reconciler novelty)
(om.next/merge! reconciler novelty query)

Merge in novelty into the reconciler. The novelty should be in the correct shape (normalized or denormalized) depending the reconciler configuration. Affected component will be queued for re-render. Query is useful when defining a custom :merge function for the reconciler.

app-state

(om.next/app-state reconciler)

Return a reference to the atom managed by the reconciler. Useful when reconciler state was initialized with plain data.

app-root

(om.next/app-root reconciler)

Return the application's root component.

from-history

(om.next/from-history reconciler
  #uuid "894e7a30-a5b8-4751-8bd6-a51aa122a919")

When mutating the application state via transactions or query modifications, Om will log a UUID associated with an application state before the change was applied. You can use the UUID to recover a previous application state. Useful for "Fix & Continue" development workflows.

Remote Integration

The following functions are useful when building integration with remote data sources and services.

tempid

(om.next/tempid)
;; #om/id[...]

Returns a unique ID. If a remote transaction offers :tempids these will be transitioned in the client to stable IDs.

reader

(om.next/reader)

Return a transit JSON reader capable of handling tempids. Can provide a map of the standard options as the only argument.

writer

(om.next/writer)

Return a transit JSON writer capable of handling tempids. Can provide a map of the standard options as the only argument.