Fork me on GitHub
#reagent
<
2021-01-29
>
jaime00:01:16

Hi all, is this a bug or expected behaviour? I'm expecting props=nil children=["Bar"] instead of props="Bar" and children=nil I thought, props will have value only when second element in hiccup vector is a map?

; Given I have component
(defn foo [props children]
  [:div props children])

And I render like
[foo "Bar"]

p-himik00:01:26

It is expected. You have created a component that requires two arguments but you have provided only one.

jaime00:01:17

Thanks for confirming. I'm trying to create text component with api like:

[text {:variant :primary
       :style {:some "style"}}
  "Some Text"]

[text "Hey"]
Is there a way I can improve below code?
(def text-styles {:variants {:primary {:color (value :colors :primary :700)}}})
(defn text []
   (let [this (r/current-component)
         {:keys [variant style]
          :or {variant :default}} (r/props this)]
     (into [:> rn/Text {:style (merge
                                 (variant-style text-styles variant)
                                 style)}] (r/children this))))

jaime00:01:22

In the above code I'm not using the parameters to get the props and children

p-himik00:01:17

I'm still not sure what you're after. You say you're trying to create a component with two arguments. But your example has a component with no arguments. My brain cannot magically reconcile the two. If you want optional arguments, you can use multi-arities or a map with optional keys. That's all I can say right now.

jaime20:01:58

Sorry for the confusion... "If you want optional arguments, you can use multi-arities or a map with optional keys. That's all I can say right now." Actually the multi arity is what I'm trying to avoid, because then I have to check if the first param is map (meaning its a props), otherwise its a child, and if second param also has value, then I have to combine first and second param as child. Lets say if I made it this way..

(defn text [props & children]) 
;; props is "Hey", children is nil
[text "Hey"]

;; props is map, children is (("Hey"))
[text {:style {:fontSize 16}} "Hey"]

;; props is map, children is ([text "Hey"])
[text {:style {:fontSize 16}} [text "Hey"]]

;; props is [text "Child 1"], children is ([text "Child 2"])
[text [text "Child 1"] [text "Child 2"]]

;; props is map, children list of [text]
[text
      {:style {:color "red"}}
      [text "with color Child 1"]
      [text "with color child 2"]]

jaime20:01:53

In the above example, I have to handle inconsistency of the params (props and children) if I will be using the function params. And what I'm trying to point out is, its better not to use the params, and just rely on (r/props) and (r/children) to get consistency. (Consistency here meaning, props will always be a map, and first children will not be in the props function param in cases I did not pass style map in the component), reagent knows it is a children

p-himik21:01:28

You don't have to check anything if you don't have the same arity that accepts different types:

(defn my-view
  ([arg] ...)
  ([arg1 arg2] ...))

p-himik21:01:59

But it won't work if you want to be able to accept varargs.

p-himik21:01:38

And if you do want that, you have pretty much outlined the available options yourself.