Fork me on GitHub
#helix
<
2022-08-11
>
geraldodev00:08:01

Hi folks, long time I don't ask you anything. Hope you are well. I'm trying to use v7 react-hook-form and its register function returns the props to be used by the input. the createElement "input" works because I'm passing a js object straight to props as argument, the (input (register "name")) does not work because its wired to pass nil as props https://github.com/lilactown/helix/blob/master/src/helix/dom.cljc#L172 because the $d macro process props just if they are a clojure map. Wouldn't be the case to accepting (object? props) and pass it to createElement as props without processing instead of nil ?

(.createElement r "div"
                    (.createElement r "label" "ID")
                    (.createElement r "input" (register "id"))

                    (label "name")
                    (input  (register "name")))

geraldodev01:08:10

I think the trick does not apply here, because I'm not invoking $ (which is create element) and because it is a js object that is returned by register.

Jimmy Miller01:08:02

I guess I'm just confused why not use $ with &. Pretty sure that works even if the thing returned to & is a js object. Could be wrong though

geraldodev01:08:30

The $d macro that generates the react-dom call does not expect props other than clojure map.

lilactown01:08:06

Hmm the $d macro ought to work the same as $. If not, please file a bug

lilactown01:08:07

We started using react-hook-form at work recently. We have a thin wrapper around it. I'll look at it tomorrow

geraldodev01:08:15

Cannot say that they are different, because $ also ignores js object props https://github.com/lilactown/helix/blob/0ffa64c592aa46bdde8cc24d1ef71cf4cc0bd930/src/helix/core.clj#L57 and I think that is by design.

Jimmy Miller01:08:34

Yeah but by passing it like {& (register "name")} the argument is a map

Jimmy Miller01:08:01

So you go down the other path. And the props should all get passed fine.

geraldodev01:08:56

@jimmy I've tried that {:& (register "name")}

lilactown01:08:59

Open a bug with a repro then please. That should work

lilactown01:08:13

That works in our app

geraldodev01:08:41

The whole $ thing is you pass a map and it amasses a js object with a clojure interface. So it just processes props when its called with a clojure map as argument. And that is great because we call ($ ReactSelect {:funkyProperty "string"} and it generates the js object at compile time of that call. If I already have a JS object it treats as children, both in $ and $d the behaviour is consistent with each other, because both assume children, and incosistent with the (if (map? props)) pathway which accepts properties.

lilactown01:08:11

that's wrong

lilactown01:08:29

or maybe we are misunderstanding each other

lilactown01:08:49

($d "div" {:& (register "foo")})
works

lilactown01:08:36

just like

($d "div" {:& #js {:on-click #(js/alert "hi")})
works

lilactown01:08:13

if you can show a repro for this breaking, you should create a bug

lilactown01:08:26

so it can be fixed, because it should work

👍 1
lilactown01:08:16

> If I already have a JS object it treats as children this is true if you are passing it bare, without using the "spread props" syntax that @U5K8NTHEZ was saying

lilactown01:08:37

($d "div" (register "foo"))
will not work, because it will treat the JS object as a child

geraldodev01:08:41

That's why I tried initially, because that makes more sense

geraldodev01:08:14

if I already have a js object why wrap it with a clojure map

lilactown01:08:49

See the link that jimmy posted as the first reply in this thread

lilactown01:08:36

it's a quirk of helix's syntax to allow writing props as maps normally with as little runtime processing as possible. you can always macro expand the $ to inspect what it is doing

lilactown01:08:17

it's not very often that you want to forward all props without some additional overrides, as well. using the {:& (register "foo")} syntax allows you to easily add more props to the element later

Jimmy Miller01:08:35

Yeah, just tried this out in a test app. It all worked fine for me.

(ns test-react-hook-form.main
  (:require [helix.core :as h]
            [helix.hooks :as hooks]
            [helix.dom :as d]
            ["react-dom/client" :as rdom]
            ["react-hook-form" :as form]))


(h/defnc app []
  (let [form (form/useForm)
        register (.-register form)
        handle-submit (.-handleSubmit form)
        on-submit (fn [data] (println data))]
    (d/form {:onSubmit (handle-submit on-submit)}
            (d/input {:& (register "name")})
            (d/input {:type "submit"}))))
 

(defn init []
  ;; start your app with your favorite React renderer
  (-> (rdom/createRoot (js/document.getElementById "app"))
      (.render (h/$ app))))

lilactown01:08:42

the weird syntax for $ is confusing for a lot of people. I onboard a lot of people to it. This kind of case catches people a lot the first time they encounter it

lilactown01:08:38

you're not alone geraldodev for not falling into the pit of success, nor for wishing that it worked differently

Jimmy Miller01:08:51

For what its worth, after using helix for the last few years, I’ve grown to love the $ syntax. IMO very smart tradeoffs of not a lot of abstraction, but also good performance with little to no interpretive overhead.

👍 1
geraldodev02:08:08

I like $ also, its a createElement on steroids. thank you folks.

geraldodev00:08:23

when we call register it generates various input props