reagent

Schmoho 2025-02-11T10:55:26.976629Z

I can't get functional components in Reagent (1.2.0, React 17.0.2) to work 😕 Does somebody know how to do that? I am trying to translate this part of the ApolloClient intro (mostly just using a wrapping Provider component and a hook): https://www.apollographql.com/docs/react/get-started#step-4-connect-your-client-to-react I figured it should look something like this:

(def functional-compiler
  (reagent.core/create-compiler {:function-components true}))

(defn simple-component []
  [:div "Hi"])

(defn load-component [query]
  (let [{:keys [data]} (useQuery query)]
    (fn [query]
      [:div data])))

(defn init! []
  (reagent.core/set-default-compiler! functional-compiler)
  (rdom/render [ApolloProvider (clj->js {:client client})
                #_[load-component my-query]
                [simple-component]]
               (.getElementById js/document "root")))
When I do that nothing really renders and the react devtools tell me the children for the apollo provider are undefined:

p-himik 2025-02-11T11:00:36.510259Z

FWIW, I myself would try with the default compiler first and with adding :> in front of ApolloProvider.

juhoteperi 2025-02-11T11:01:30.480009Z

functional components can't be used for interop, you still need :> for React components

juhoteperi 2025-02-11T11:02:18.307499Z

functional components option is for creating function components from Reagent functions, so you can use hooks in your own components without referring to those components using :f>

Schmoho 2025-02-11T11:25:23.584029Z

Okay - thanks! I still don't quite understand what the correct way to go about this is though. The function components seem to trickle down and make a lot of things kinda difficult. In particular, this code with which I ended up now:

(defn load-component [query]
  (let [{:keys [loading error data]} (useQuery (.-children query))]
    (fn [query]
      (cond
        loading
        [:> :div "Loading..."]
        error
        [:> :div "Error: " (str error)]
        :else
        [:ul
         (for [item (get-in data [:data :items])]
           ^{:key (:id item)} [:> :li (:name item)])]))))

(defn init! []
  (rdom/render
   [:> ApolloProvider {:client client}
    [:> load-component my-query]]
   (.getElementById js/document "root")))
doesnt render, probably because: Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it. it seems kind of limiting not to be able to use type II components here?

juhoteperi 2025-02-11T11:26:39.005739Z

load-component is a reagent component, :> is for React component interop

juhoteperi 2025-02-11T11:26:52.005869Z

also you can't use form-2 with a hook like that

juhoteperi 2025-02-11T11:27:14.845199Z

(defn load-component [query]
  (let [{:keys [loading error data]} (useQuery (.-children query))]
      (cond
        loading
        [:> :div "Loading..."]
        error
        [:> :div "Error: " (str error)]
        :else
        [:ul
         (for [item (get-in data [:data :items])]
           ^{:key (:id item)} [:li (:name item)])])))

(defn init! []
  (rdom/render
   [:> ApolloProvider {:client client}
    [:f> load-component my-query]]
   (.getElementById js/document "root")))

juhoteperi 2025-02-11T11:28:12.397899Z

you could use hooks with form-2 and :f> but the hooks must be in the inner fn

Schmoho 2025-02-11T11:35:09.429919Z

Mh thanks for your help, I got it to "work" now I guess, I'll see if I actually can understand it too

juhoteperi 2025-02-11T11:36:54.142719Z

Use :> only with JS React components. Use [:f> foo] instead of [foo] if your cljs Reagent component wants to use hooks. Hook uses need to be in the "render fn" (the inner fn for form-2 components.) I haven't ever used set-default-compiler! to switch to function components by default, instead just using :f> when needed.

Schmoho 2025-02-11T11:42:03.662129Z

Okay, I'll see how far I get

Schmoho 2025-02-11T11:42:20.676849Z

Thanks a lot