Fork me on GitHub
#reagent
<
2021-07-26
>
nbdam07:07:01

Hi, I have a problem with reagent/react which surfaces after shadow-cljs upgrade from from 2.12.5 to 2.15.2 (this is only change made). I get react (reagent) error 'Invalid hook call. Hooks can only be called inside of the body of a function component.' I am embedding functional component in reagent app and it is all working fine on older versions. Upgrade from older reagent versions to 1.0 and 1.1 went smoothly. This version of shadow-cljs upgrades clojurescript from 1.10.844 to 1.10.879. Has anyone else encountered this? Not sure where to file bug report...

p-himik07:07:44

Can you create a minimal reproducible example?

nbdam06:07:39

I tried to make minimal example, but still haven't managed to do so. My current efforts make me think it may be something to do with forwardRef. I have attached sample react component which is similar in principle to the real one I am having problems with. (two versions). I obviously don't understand how to use from cljs. I either get Invalid hook error or 'Expected something callable' from reagent. I have tried using it with ':>' and ':f>'

p-himik07:07:21

No clue, sorry.

edo11:07:59

I have a question folks. Is there something wrong with this code? I pass a color to the icon-button component. It gets into button-styles and in the browser, if I inspect the element, class names are correct. In spite of it, button doesn’t render a background color :thinking_face:. Maybe it’s some tailwind shenanigan.

(ns bm.components.icon-button
  (:require [clojure.string :refer [join]]))

(def common-button-styles "flex items-center justify-center text-gray-100 font-semibold px-2 py-1 rounded-sm shadow-md w-8 h-8")

(defn button-styles
  [{:keys [color]}]
  (if color
    (join " " [common-button-styles (str "bg-" color "-600") (str "hover:bg-" color "-700")])
    (join " " [common-button-styles "bg-purple-800 hover:bg-purple-900 hover:text-white"])))

(defn icon-button
  [{:keys [icon on-click color]}]
  [:button {:class (button-styles {:color color})
            :on-click on-click}
   [:> icon {:class "w-3 h-3"}]])

p-himik11:07:10

> class names are correct. In spite of it, button doesn’t render a background color That's what the right side of the dev tools is for. It has all the styles applied to the component being inspected, including styles that were superseded by others with higher priority. If your class name is there, then the color was superseded - you can check by what. If your class is not there, then the browser simply doesn't know about it. Probably the right CSS was not loaded.

p-himik11:07:34

Also, the hover:something class names sound as if they are not class names but a combination of the :hover selector with a class name. If so, you can't really use it like that. But I could be wrong - Tailwind could create special rules for the :hover selector with all the possible hover:something classes.

edo11:07:27

If I hardcode a color in the button-styles function, it works, so I think it’s not being superseded :thinking_face: . Is there a possibility that for some reason the evaluation of the color variable doesn’t arrive on time for the css to be properly injected?

edo11:07:50

hover:bg-red-500 is correct according to tailwind class names.

p-himik11:07:56

If you hard-code something in :style, it gets the highest priority so it supersedes anything.

p-himik11:07:24

CSS has no timing - if you change CSS after the fact, the new results will still be visible.

edo11:07:36

True, i get your point. going to investigate what’s happening there :thinking_face: Is join a good approach to mix the strings with a ” ” ?

p-himik11:07:43

And you said it yourself - you do see the right class in the Elements inspector. So the CLJS code is working. Meaning, something is wrong with the CSS.

3
p-himik11:07:19

If you're using Reagent, just use reagent.core/class-names - then you can use strings, keywords, nils. So code like this becomes possible:

(r/class-names [:a (when b? :b) "c"])

(r/class-names [:a] [:b :c])

❤️ 3
👀 3
alexdavis12:07:41

It's possible you have some purgecss process which is removing the tailwind css you want, you're not supposed to do (str “bg” foo) because then purgecss (or whatever) doesn't know you are using that class. https://tailwindcss.com/docs/optimizing-for-production#writing-purgeable-html

edo13:07:30

Ooh, that explains a lot. After removing join and str and using r/class-names problems went away :thumbsup:

javi11:07:17

also, for future reference as you may come across this gotcha when working with classes in reagent...

[:div.bg-yellow-300  ;; <-- this takes precedence
 {:class "bg-red-300"}
 123123
 ]

p-himik11:07:21

Prohint: don't use shortcuts such as :div.my-class or :div#my-id. :) It's easy, but there are three major downsides: • The implicit precedence mentioned above • Needs to be rewritten into a proper map when you need to toggle some class in runtime (and you will eventually need to do that) • Impossible to use proper keyword search - you will have to use an inferior text search Another downside which depends upon your editor - it will now offer to autocomplete not only :div, but also all the divs with all the classes and IDs. It's definitely a downside when you have hundreds of combinations.

👍 2
edo11:07:09

Thanks for all your valuable input everyone. It’s so good to meet a community like this one. Loving it. ❤️

🙂 4
Mitul Shah20:07:22

@U2FRKM4TW do you know where i can find other examples of r/class-names being used? looks interesting

p-himik21:07:04

Not sure about the examples, but you can just go through its source code, it's rather trivial.

edo17:07:48

Hey folks. For everyone finding this issue I’d just discovered we don’t need r/class-names. Passing {:class [“hardcoded class names” variable-class-name1 variable-class-name2]} does the job.

edo17:07:00

What I mean with this is that a space is added in-between the strings.

p-himik17:07:23

Oh, even to [:> some-react-component ...]? Sweet!

Mitul Shah17:07:12

oh good catch! what about conditionals? (when x? variable-class-name1) works in between it?

p-himik17:07:02

If :class [...] works then yes, that should work as well, since it seems that Reagent uses class-names for all components.

🙌 2
edo17:07:47

Need to test it. I’ll be back here soon 🐱

edo17:07:33

Apparently reagent docs state it works https://github.com/reagent-project/reagent/blob/master/doc/UsingHiccupToDescribeHTML.md, but as I’m still a clojur’noob I’m having problems with it lol.

edo17:07:03

(defn button
  [{:keys [label color]}]
  [:button {:class ["text-white font-semibold px-2 py-1 rounded-sm shadow-sm"
                    (if color (join " " [(str "bg-" color "-500") (str "hover:bg-" color "-600")]) "bg-purple-800 hover:bg-purple-900")]
            :on-click #(js/console.log "click click")} label])

edo17:07:08

This worked for me ☝️

edo17:07:38

But I believe there must be a better way to write it than join and string… not sure.

p-himik17:07:21

You can use two ifs or one into with a single if:

(into [:class1 :class2]
  (if x?
    [:x1 :x2]
    [:y1 :y2]))
No need for space-separated strings at all.

edo18:07:21

Doubt: in this code example we’re gathering the result of the if with [:class1 :class2]. But why do you use keywords :class1 :class2 if class-names are strings?!? :thinking_face:

edo18:07:17

Is :class1 just a way of representing any variable?

p-himik18:07:25

r/class-names converts keywords to strings.

edo18:07:35

ooh I see! :thumbsup:

p-himik18:07:15

> (reagent.core/class-names [:class1 :class2 nil :class4])
"class1 class2 class4"

edo15:08:41

Coming back here to share this concern about using dynamic values with tailwind 😞 https://tailwindcss.com/docs/just-in-time-mode#known-limitations. Check the Dynamic values section where it says one shouldn’t use string concatenation to create class names 😞

Mitul Shah16:08:32

but that’s not what you’re doing? we use tailwind too and i’ve been using this fine

{:class ["p-4 mt-2" (if(dark? "bg-black" "bg-white")]}

✔️ 2
edo14:08:13

That’s fine, what’s not so fine is

{:class [(str "bg-" color "-500")] }

edo14:08:50

But since I’ve updated tailwind to the most recent versions it’s working :thinking_face: