Fork me on GitHub
#rum
<
2017-02-25
>
odie03:02:33

Howdy! Can anybody point me toward some resources on how interop works with other react components?

odie03:02:56

more specifically, I’m trying to make use of semantic-ui-react components… although the rum wiki (https://github.com/tonsky/rum/wiki) suggests I should create a function to wrap the createElement call… I don’t know how to use it with rum’s “Hiccup-like” syntax...

martinklepsch06:02:49

@odie

(defn create-element [react-comp opts & children]
  (apply js/React.createElement react-comp (clj->js opts) children))

(def flipmove* (partial create-element js/FlipMove))

martinklepsch06:02:11

and then you just do (flipmove* {} …)

odie06:02:49

@martinklepsch Thanks for that! But… it doesn’t seem to work with the sablono markup though… Console says “Uncaught Error: … A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object."

odie06:02:30

sorry~ been digging a bit through rum and sablono trying to figure out what exactly is being expected in the in the tag position in a [tag attr & children] form...

odie06:02:08

Rum’s defc seem to return something that works fine when used with sablono...

martinklepsch08:02:47

@odie one reason could be that you accidentally use [flipmove* …] instead of (flipmove* …)

odie08:02:35

can I attach additional children with (flipmove* …)?

martinklepsch08:02:16

(flipmove* {:this :are-props} (this-is-a-child-component) (another-one))

martinklepsch08:02:16

that’s roughly how I use it

odie08:02:31

thanks, man… this is honestly all quite confusing…

odie08:02:16

spent lots of time looking at this… I think I found a workable solution...

martinklepsch08:02:24

@odie if you have a snippet of code that demonstrates your issue I can take a look for any obvious misunderstandings

odie08:02:47

basically, I was trying to mix normal sablono syntax with components from semantic-ui-react…

(rum/defc FriendList-Item < rum/static
  [friend-data]

  (card {:href (bidi/path-for routes :collab-game-select)}

        [:div {:class "image"}
         [:img {:src (friend-data "avatarfull")}]]

        [:div {:class "content"}
         [:div {:class "header"} (friend-data "personaname")]]
… omitted

odie08:02:14

where the “card” call on the 3rd line is a react component from semantic-ui

odie08:02:28

I think your solution works if I’m not trying to attach additional sablono markup...

martinklepsch08:02:57

so card is a React component. It doesn’t know about Hiccup, Clojurescript datastructures or anything. The only thing it understands is React components.

martinklepsch08:02:35

if you make another component FriendList-Image-And-Content that contains the stuff after the {:href …} map then you could pass that to the card component

martinklepsch08:02:03

invoking (FriendList-Image-And-Content) will return a react component which can be understood by the card component that you’re using

odie08:02:01

I just found an approach that works… This is not to take away from all the help you’ve given… I deeply appreciate having someone to talk to while scratching my head over this… anyway… I’ll leave it here in case anybody is having the same issues… x_x

martinklepsch08:02:42

sure, great if you found something thats working

odie08:02:49

adopted from https://github.com/madvas/cljs-react-material-ui/blob/a2119fdaaf3e8255b6182eb619faf00eb291a5ef/src/cljs_react_material_ui/core.clj Approximately...

(ns app.core
  [camel-snake-kebab.core :as cs :include-macros true]
  [camel-snake-kebab.extras :refer [transform-keys]])

(def props-kebab->camel->js (comp clj->js (partial transform-keys cs/->camelCase)))

(defn create-mui-cmp
  ([react-class args]
   (let [first-arg (first args)
         args (if (or (map? first-arg) (nil? first-arg)) args (cons {} args))]
     (apply js/React.createElement react-class
            (props-kebab->camel->js (first args)) (rest args))))
  ([root-obj type args]
   (create-mui-cmp (aget root-obj type) args)))

(defn adapt-rum-class [react-class]
  (fn [& args]
    (let [[opts children] (if (map? (first args))
                              [(first args) (rest args)]
                              [{} args])
          type# (first children)]
      (let [new-children (if (vector? type#)
                            [(sablono.interpreter/interpret children)]
                            children)]
        (create-mui-cmp react-class (cons opts new-children))))))

(def card (adapt-rum-class js/semanticUIReact.Card))

odie08:02:47

I guess what’s different is that it uses sablono to evaluate the rest of the children...

odie08:02:21

I pulled in as little from the cljs-react-material-ui as possible...

odie08:02:40

I’m surprised a utility like this isn’t already a part of rum… it seems natural to want to pull in external components and still be able to mix it using sablono

odie08:02:18

incidentally, adapt-rum-class in the cljs-react-material-ui repo was fixed up by a tonsky recently...

martinklepsch09:02:06

@odie What does this code give you over the alternative I outlined above?

odie09:02:12

with this piece code, you’re able to mix in sablono style markup directly...

odie09:02:10

as in… you can attach children that are in sablono style markup...

odie09:02:57

honestly… the solution looks like has more to do with sablono than rum… (now that I’m slightly more informed than I was at the beginning of the day…)

martinklepsch09:02:15

In my book using the extra component is cleaner 😛

odie09:02:20

alrighty~ this approach gives the user the freedom to choose… 😃 In this case, it’s just a card that represents some info about the user… it’d be strange to think of the “inside” of the card as another component… 😃

misha09:02:51

@odie I use the same (partial create-element ... approach for react native (no sablono there)

odie09:02:31

I’m really new to both clojurescript and react… so still learning what’s what! 😃