reagent 2025-02-11

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:

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

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

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>

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?

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

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

(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")))

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

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

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.

Okay, I'll see how far I get

Thanks a lot