> 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.

Reply via email to