Skip to content
This repository has been archived by the owner. It is now read-only.
Switch branches/tags
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


Peon is a small library to support idiomatic dispatch of Om Next transactions from stateless components.

Traditionally, statelful components send handlers down to stateless compoenents via mechanisms such as om/computed. This approach offers great isolation as well as the ability to reuse and test components more granularly.

Peon takes that approach further by creating a simple idiomatic protocol for dispatching actions from stateless components up the component tree to stateful components.

Table of Contents

Getting Started

Add the following dependency to your project.clj file:

Clojars Project


Require peon.core on your stateful component:

(ns my-project.components.stateful
  (:require [ :as om :refer-macros [defui]]
            [om.dom :as dom]
            [my-project.components.stateless :as stateless]
            [peon.core :as peon]))

Use the protocol peon/IDispatcher to specify which handlers this stateful component is responsible for.

The dispatcher interface must return a map where each keyword points to a handling function.

(defui RootComponent
  static om/IQuery
  (query [this] `[:app/details ~(om/get-query stateless/HeaderComponent)])
  (dispatcher [this] {:change-header #(om/transact! this '[(app/change-details! {:app/header "New header})])
                      :no-params #(println "handler with no params")
                      :two-params #(println "param 1:" %1 "and param 2:" %2)})
  (render [this]
          (let [{:keys [app/details]} (om/props this)]
            (dom/div nil
                     (stateless/header details)))))

(def root (om/factory RootComponent))

The component above handles three actions: :change-header, :no-params and :two-params. The latter two simply print something out while the first one transacts an hypothetical mutation.

Then, on your stateless component, make sure to require peon.core:

(ns my-project.components.stateless
  (:require [ :as om :refer-macros [defui]]
            [om.dom :as dom]
            [peon.core :as peon]))

You can then dispatch actions using peon/dispatch. The signature takes this followed by the keyword of the handler and optionally any arguments you want to pass to the handler.

(defui HeaderComponent
  static om/IQuery
  (query [this] '[:app/header])
  (render [this]
          (let [{:keys [app/header]} (om/props this)]
            (dom/div nil
                     (dom/h1 nil header)
                     (dom/button #js {:onClick #(peon/dispatch this :change-header)} "Change header")
                     (dom/button #js {:onClick #(peon/dispatch this :no-params)} "No params")
                     (dom/button #js {:onClick #(peon/dispatch this :two-params "Don't panic!" 42)} "Two params")
                     (dom/button #js {:onClick #(peon/dispatch this :not-found)} "Not found")))))

(def header (om/factory HeaderComponent))

For representation sake, we've got four buttons here - three of which dispatching to the handlers we defined on the parent component, and a random one that is not going to be found anywhere on the tree.

How does it work?

Peon will look for any component on the component hierarchy (starting with the current component) that implemenets peon/IDispatcher. When it finds one, it will check whether the handler keyword is available. If it is, it gets dispatched, if not the algorithm continues to traverse up the hyerarchy until it exhausts the tree. In that case, a warning is printed on the console because probably that's not what you want.


If you find a bug, submit a Github issue.


This project is looking for team members who can help this project succeed! If you are interested in becoming a team member please open an issue.


Copyright © 2017 Tiago Luchini

Distributed under the MIT License.


Idiomatic dispatch of Om Next transactions from stateless components





No packages published