Fork me on GitHub
#reagent
<
2020-02-18
>
defa09:02:10

I’m trying to use React Hooks in a react native app based on reagent/re-frame but I get the following error:

2020-02-18 10:29:17.953 6617-6652/com.origami E/ReactNativeJS: Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
    1. You might have mismatching versions of React and the renderer (such as React DOM)
    2. You might be breaking the Rules of Hooks
    3. You might have more than one copy of React in the same app
    See  for tips about how to debug and fix this problem.
Here is the code snippet:
(ns 
    (:require
        ["react-native" :as react-native]
        [react :as react]
        ...))

(defn root []
  (let [useState (.useState react 0)]
    [:view 
     ...
     ]))
Maybe it is a version mismatch as stated in the error but I think I’ve set up dependencies correctly. Is it the wrong place to use the hook? I’m using shadow-cljs so some deps are loaded via deps.edn like reagent {:mvn/version "0.9.1"} which pulls in react 16.9.0 via CLJSJS and then I have my package.json for the react-native app which references "react": "16.9.0" … so I guess I should be fine, since it is the same version of react?

juhoteperi09:02:54

Solution for now, is to just use RAtom to store state, if you don't specifically need hooks for interop.

defa09:02:58

I’m using react-navigation and was looking for clean and easy way to navigate using re-frame events. Therefore I tried using the useNavigate hook (https://reactnavigation.org/docs/en/use-navigation.html), so r/atoms will not help I guess.

juhoteperi09:02:35

ReactFeatures doc mentions the same workaround as ReactNavigation doc, wrapping the class component inside functional component which uses the hook.

👍 8
defa09:02:50

Seems that I have overlooked that in the docs, will try to make it work. Thanks, @juhoteperi! UPDATE: works for the useState hook in the example. Again, thanks, @juhoteperi!

Yehonathan Sharvit14:02:02

I would like to understand why some react cljs libs use a macro rather than function to create react components and why don’t. It seems that reagent doesn’t use a macro for this while hicada https://github.com/rauhs/hicada and helix https://github.com/Lokeh/helix/blob/master/docs/creating-elements.md#-macro do. Is it for performances reasons (like converting props from clj to js) or is there another reason?

juhoteperi14:02:37

Yes, macros can be more performant but the implementation is more complex and user needs to call the macro so it makes to code more verbose

Yehonathan Sharvit15:02:33

My question is: why hicada and helix use macros?

lilactown15:02:00

For helix, this is answered in the FAQ Tl;dr is that using React's local state feels the performance problems of dynamic hiccup parsing more than Reagent does

lilactown15:02:26

Because React local state always renders the entire element tree where the state is shared. Reagent can be more selective of what components rerender based on state changes

lilactown16:02:46

Hicada is just a way to do hiccup that has less performance impact, but with some expressivity tradeoffs. I don't think it's more nuanced than that