keechma.ui-component
->UIComponent
(->UIComponent component-deps subscription-deps renderer)
constructor
(constructor opts)
Createas a UIComponent record. Accepts opts
as the argument. opts
is a map that can have the following params:
:component-deps
- Which child component is this component dependent on:subscription-deps
- Which subscriptions is this component dependent on:topic
- On which topic should this component send commands (to the controller):renderer
- A renderer function (Reagent component)
The UIComponent record is a way to list all the dependencies for a component. When the application is started each component’s renderer function will be partiall applied with a verion of it’s UIComponent that has the component and subscription dependencies resolved.
This allows you to write components that are completely decoupled from the rest of the application.
When you want to resolve injected component or subscription dependencies, you can use the functions defined on the UIComponent
protocol:
(def render [ctx] ;; `ctx` is a UIComponent with resolved dependencies
(let [child-component (component ctx :component-key)
subscription (subscription ctx :subscription-key)])
(def component (constructor {:renderer render
:component-deps [:component-key]
:subscription-deps [:subscription-key]))
IUIComponent
protocol
IUIComponent protocol defines functions that can be called on the UIComponent records.
members
redirect
(redirect this params)
Redirects page to the URL generated from params
send-command
(send-command this command)
(send-command this command args)
Sends a command to the controller.
subscription
(subscription this key)
(subscription this key args)
Returns a subscription based on the key.
report
(report this name payload)
(report this name payload path)
(report this name payload path severity)
current-route
(current-route this)
Returns a current route data. It will use the :current-route-fn
that is injected from the outside to return the data.
component
(component this key)
Returns a component based on the key.
renderer
(renderer this)
Returns a component renderer function that has the component record partially applied (ctx
) as the first argument.
url
(url this params)
Returns a URL based on the params. It will use the :url-fn
that is injected from the outside to generate the URL based on the current app routes.
make-ex
(make-ex msg)
map->UIComponent
(map->UIComponent G__14575)
resolve-component-dep
See resolve-dep
resolve-dep
(resolve-dep dep-kw coll-kw component key component-dep)
Resolves a dependency on the UIComponent record. Returns a new version of the record with the resolved dependency.
(def news-component (constructor {:component-deps [:user-profile :similar-news]
:subscription-deps [:current-news :comments]}))
(resolve-dep :subscription-deps :subscriptions news-component :current-news (fn []...))
;; Returns a new version of the `news-component` with the :current-news subscription resolved
(resolve-dep :component-deps :components news-component :user-profile user-profile-component))
;; Returns a new version of the `news-component` with the :user-profile component resolved
Two shorthand functions are defined that allow you to omit first two arguments:
resolve-subscription-dep
- Resolves a subscription dependencyresolve-component-dep
- Resolves a component dependency
resolve-subscription-dep
See resolve-dep.
system
(system components)
(system components subscriptions)
Creates a component system.
Component system is a group of components that are interdependent. Each component system must define a :main
component which will be returned from the system
function.
system
function resolves dependencies between components.
For example, let’s say that your application consists of three components:
- layout
- sidebar
- chat room list
Layout is rendering the sidebar component and sidebar component is rendering the chat room list component.
Chat room list component has a subscription dependency on :chat-rooms
which will return the list of chat rooms to render.
Usually you would either pass the chat rooms subscription from layout to sidebar to the chat room list component, or the chat room list component would have a dependency on a global :chat-rooms
subscription.
Keechma allows you to avoid both of these problems:
- only the chat room list component will know about it’s dependencies
- the dependencies will be injected from the outside by the
system
function
(defn layout-renderer [ctx] ;; ctx is `layout-component` record with resolved dependencies
[:div.main
[:div.sidebar [(component ctx :sidebar)]]]) ;; Resolve the `:sidebar` component
(def layout-component (constructor {:component-deps [:sidebar]
:renderer layout-renderer}))
(defn sidebar-renderer [ctx]
[:div.sidebar
[(component ctx :chat-room-list)]) ;; Resolve the `:chat-room-list` component
(def sidebar-component (constructor {:component-deps [:chat-room-list]
:renderer sidebar-renderer}))
(defn chat-room-list-renderer [ctx]
(let [chat-rooms (subscription ctx :chat-rooms)])) ;; Resolve the `:chat-rooms` subscription
(def chat-room-list-component (constructor {:subscription-deps [:chat-rooms]}))
(def main-component (system {:main layout-component ;; Map compnents to keys
:sidebar sidebar-component
:chat-room-list chat-room-list-component}
{:chat-rooms (fn [app-state-atom])})) ;; Map subscriptions to keys
In the example above main-component
will be a Reagent component that can be mounted into the DOM, with all of the dependencies between components resolved.
system
function provided everything that components need from the outside, and all of the components are reusable by design.