> 1) Difficulty of passing children (as in React's props.children)
You can pass children via the :opts key:
(defn some-component [data owner child]
(reify om/IRender
(render [this]
(dom/div nil
(dom/h1 nil "A child component:")
(om/build child data)))))
(om/build some-component data {:opts child-component})
On Thursday, August 7, 2014 1:51:03 AM UTC+3, Tom Connors wrote:
> While Om improves significantly over plain React, there's 2 related problems
> I've been running into that I'd like to hear other opinions on.
> 1) Difficulty of passing children (as in React's props.children)
> 2) Custom component construction syntax does not mirror DOM element
> construction syntax
>
> This is easier for me to explain with code, so I wrote up an example. Let's
> assume the only way I can get something vertically centered is with a couple
> wrapper divs, and I want to make that solution reusable with a component.
>
> ;; What I would ideally like to write is this:
> (defn vertically-center
> "Vertically centers its children"
> [data owner]
> (reify
> om/IRender
> (render [_]
> (dom/div #js {:className "vertical-center-outer-wrapper"}
> (dom/div #js {:className "vertical-center-inner-wrapper"}
> ;; include the component's passed-in children,
> ;; be they dom elements or custom components
> (aget owner "children"))))))
>
> ;; elsewhere, in another component's render fn (still in my idealized world):
> (dom/div #js {:id "whatever"}
> ;; construct without build.
> ;; Syntax for constructing components is very similar to syntax for
> ;; constructing dom elements.
> ;; It might even by nice to be able to omit the cursor as well,
> ;; when it isn't needed.
> (vertically-center some-cursor
> ;; pass in children directly
> (dom/p #js {:className "my-vertically-centered-p"}
> "Some Text")))
>
> ;; The only way I know to accomplish that in the real world is the following:
> (defn vertically-center [data owner]
> (reify
> ;; Need to use :state to account for the possibility that the children
> ;; list will change over the lifetime of this component
> om/IRenderState
> (render-state [_ {:keys [children]}]
> (dom/div #js {:className "vertical-center-outer-wrapper"}
> ;; I can include children without apply because it's a js array
> (dom/div #js {:className "vertical-center-inner-wrapper"}
> children)))))
>
> ;; elsewhere, in another component's render fn
> (dom/div #js {:id "whatever"}
> ;; need to use build for custom components
> (om/build vertically-center some-cursor
> ;; This is wordier than passing children directly.
> {:state
> {:children #js [(dom/p #js {:className
> "my-vertically-centered-p"}
> "Some Text")]}}))
>
>
> I've thought up a couple possible half-solutions:
>
> 1) A macro for component definition that turns calls to the component into
> calls to om/build the component. I tried this, and found I lack the macro
> wisdom to make it work, but what I came up with is this:
>
> (defmacro nobuild [body]
> (let [macro-name (nth body 1)
> component-name (symbol (str (name macro-name) "*"))]
> ;; add a macro to the compiler's runtime that is in the same
> ;; namespace as the calling code
> ;; and which expands to call om.core/build
> (intern *ns*
> (with-meta macro-name {:macro true})
> (fn [& args]
> `(om.core/build ~component-name ~@args)))
> ;; The actual expansion just replaces the component's name
> ;; with the one generated here.
> (~(first body)
> ~@(cons component-name (rest (rest body))))))
>
> ;; Then call it like this:
> (nobuild (defn my-component [data owner] (reify etc...)))
> ;; and calls to (my-component) could expand into calls to (om/build
> my-component)
> ;; This probably isn't such a good solution.
>
> 2) This one would require a change to Om, but om/build could take any number
> of arguments and treat any after the second as children, except the last one
> is an optional map:
>
> (defn build
> ([f cursor & children-and-maybe-a-map]
> ;; I'm not sure what would go here.
> ))
>
> I appreciate any input or advice on this topic.
>
> -Tom
--
Note that posts from new members are moderated - please be patient with your
first post.
---
You received this message because you are subscribed to the Google Groups
"ClojureScript" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/clojurescript.