Fork me on GitHub
#helix
<
2021-09-30
>
alexdavis15:09:53

Is there a way to render a sequence of components? I would expect this to work but it doesn’t

(defnc pages
  []
  ($ Routes
     (for [page-props navbar-pages]
       ($ Route page-props))
     ($ Route {:path "*" :element (d/h1 "Page not found")})))

alexdavis15:09:11

(example is using react-router)

alexdavis15:09:18

I guess this works, but let me know if theres a better way

(def route (helix/factory Route))

(defnc pages
  []
  ($ Routes
     (for [page-props navbar-pages]
       (route page-props))
     ($ Route {:path "*" :element (d/h1 "Page not found")})))

lilactown16:09:39

the first one should work. what doesn't work for you?

lilactown16:09:52

oh, it's page-props

lilactown16:09:45

@alex395 when using $, you should pass dynamic props in via the :& prop. like ($ Route {:& page-props}) . see https://github.com/lilactown/helix/blob/master/docs/creating-elements.md#dynamic-props

lilactown16:09:54

has nothing to do with sequences

alexdavis16:09:41

Ah ok that makes sense, guess I didn’t read the docs carefully enough 😅

lilactown16:09:23

that seems to trip everyone up at least once

alexdavis21:09:39

another issue, hopefully also a common easy to fix one 😛 I have a custom defnc macro:

(ns lib.helix
  #?(:clj (:require [helix.core :as helix]))
  #?(:cljs (:require-macros [lib.helix])))

#?(:clj
   (defmacro defnc [type params & body]
     (let [[docstring params body] (if (string? params)
                                     [params (first body) (rest body)]
                                     [nil params body])
           opts? (map? (first body)) ;; whether an opts map was passed in
           opts (if opts?
                  (first body)
                  {})
           body (if opts?
                  (rest body)
                  body)
           ;; feature flags to enable by default
           default-opts {:helix/features {:fast-refresh true
                                          :define-factory true
                                          :check-invalid-hooks-usage true}}]
       `(helix.core/defnc ~type ~@(when docstring [docstring]) ~params
          ;; we use `merge` here to allow individual consumers to override feature
          ;; flags in special cases
          ~(merge default-opts opts)
          ~@body))))
But when I use it, I can’t access props that are passed to the components. Heres a minimal example:
(ns some.ns
  (:require [helix.core :as helix :refer [$]]
            [lib.helix :refer [defnc]]
            [helix.dom :as d]))

(defnc foo
  [{:keys [bar]}]
  (d/p bar))

(defnc view
  []
  ($ foo {:bar 1}))
When using my defnc, I see nothing. Inspecting the params of foo tells me that the {:bar 1} map has been put into :children somehow When using helix/defnc, it works as expected

alexdavis21:09:07

My defnc is basically copied straight from the helix docs and i think it should be doing the right thing

alexdavis21:09:25

but when macros get involved my head hurts and things start to make little sense…

lilactown23:09:40

you've set :define-factory true in your custom macro

lilactown23:09:51

you should call your component like a function then, instead of using $

lilactown23:09:04

(foo {:bar 1})

alexdavis23:09:30

facepalmargh I knew it would be something like that.. where does the name factory come from? It doesn't mean anything to me, obviously I should have just read the docs but just curious why it's called that instead of something like ':call-as-function true’

alexdavis23:09:45

Also what are the disadvantages of doing this? Is it slower?