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
https://github.com/reagent-project/reagent/blob/master/doc/ReactFeatures.md#function-components
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