This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-03-10
Channels
- # announcements (1)
- # asami (44)
- # babashka (62)
- # beginners (84)
- # calva (42)
- # cider (5)
- # clj-kondo (32)
- # cljs-dev (8)
- # clojure (61)
- # clojure-australia (3)
- # clojure-berlin (1)
- # clojure-europe (12)
- # clojure-japan (3)
- # clojure-nl (4)
- # clojure-serbia (5)
- # clojure-spec (1)
- # clojure-uk (9)
- # clojurescript (31)
- # community-development (21)
- # conjure (5)
- # cursive (17)
- # datomic (14)
- # emacs (10)
- # etaoin (1)
- # figwheel-main (1)
- # fulcro (9)
- # garden (5)
- # graalvm (16)
- # helix (7)
- # honeysql (13)
- # jackdaw (25)
- # jobs (2)
- # lsp (21)
- # malli (25)
- # missionary (2)
- # mount (3)
- # off-topic (12)
- # practicalli (3)
- # re-frame (43)
- # reagent (45)
- # reitit (36)
- # releases (6)
- # remote-jobs (2)
- # reveal (28)
- # rewrite-clj (7)
- # shadow-cljs (45)
- # slack-help (4)
- # spacemacs (5)
- # sql (23)
- # startup-in-a-month (7)
- # tools-deps (59)
- # vim (26)
I’m passing in the following component as a screen (react navigation) like so:
[:> (.-Screen Stack) {:name :Feed :options {:headerShown false}
:component (as-element [home])}]
where home is the following:
(defn home [{:keys [navigation] :as props}]
(dispatch [:load-videos 1])
[safe-area-view {:backgroundColor :white :flex 1}
[:<>
(if-not @(subscribe [:videos-loaded])
;; gif requires fresco library for android
[image {:source (js/require "../resources/images/loading.gif")
:style {:top 80 :left -115 :resizeMode :cover}}]
[flat-list {:refreshControl
(as-element
[refresh-control {:refreshing @(subscribe [:refreshing])
:onRefresh #(dispatch [:load-videos 1])}])
:data @(subscribe [:videos])
:renderItem (fn [item]
(as-element
[video-press (get (js->clj item) "item")
navigation]))
:keyExtractor (fn [item]
(.-uri item))
:initialNumberToRender 4
:maxToRenderPerBatch 2
:windowSize 5
:onViewableItemsChanged (.-current (useRef (fn [viewable-items changed] (js/console.log "viewable items " viewable items
"changed " changed))))
;;#(dispatch [:load-if-at-last %1 %2])
:style {:paddingLeft 10
:paddingRight 10}}])]])
However, I’m getting the following error:
Got an invalid value for 'component' prop for the screen 'Feed'. It must be a valid react component.
How can I fix this?also I want to use
home
as a functional component because it contains the useRef hook. So my guess is that
(as-element [:f> home])
should work. But I’m getting the same error in this case as wellReact component != React element. as-element
creates a React element. I'm assuming, of course, that :component
is named aptly and expects a React component (ah, right - the error explicitly states so).
so having (reactify-component home) gives
Invalid hook call. Hooks can only be called inside of the body of a function component
so what is the solution?
The warning speaks for itself, I think. home
has to be a proper function component.
Given that you cannot use reactify-component
with a function component, I see two options:
- Wrap home
in a regular Reagent component and use reactify-component
on it
- Use the old way to create a proper function component: https://github.com/reagent-project/reagent/blob/master/doc/ReactFeatures.md#pre-10-workaround
@U2FRKM4TW what do you mean by “Wrap `home` in a regular Reagent component”?
@U2FRKM4TW that gives the following error:
Rendered more hooks than during the previous render
I changed the useRef hook to useCallable, and now I get the same error:
Invalid Hook call. Hooks can only be called inside of the body of a function component...
This suggests that the all the parents of the component that contains the hook must be functional.In that case we can’t use reactify-component at all
> all the parents of the component that contains the hook must be functional This is false.
@U01F1TM2FD5 calling reactify-component
on home
won't work, since Reagent will create a class component to wrap home
instead, treat home
like a React component:
(defn home [props]
(dispatch [:load-videos 1])
(as-element
[safe-area-view ,,,]))
I was thinking you would then pass home
in directly to the Screen Stack. the extra layer and reactify-component to convert props makes sense tho
@U01F1TM2FD5 another thing I noticed: you're using useRef
here to wrap the callback passed to onViewableItemsChanged
. why is that?
@U4YGF4NGM This is what I have now:
(defn home [{:keys [navigation] :as props}]
(dispatch [:load-videos 1])
(as-element [safe-area-view {:backgroundColor :white :flex 1}
[:<>
(if-not @(subscribe [:videos-loaded])
;; gif requires fresco library for android
[image {:source (js/require "../resources/images/loading.gif")
:style {:top 80 :left -115 :resizeMode :cover}}]
[flat-list {:refreshControl
(as-element
[refresh-control {:refreshing @(subscribe [:refreshing])
:onRefresh #(dispatch [:load-videos 1])}])
:data @(subscribe [:videos])
:renderItem (fn [item]
(as-element
[video-press (get (js->clj item) "item")
navigation]))
:keyExtractor (fn [item]
(.-uri item))
:initialNumberToRender 4
:maxToRenderPerBatch 2
:windowSize 5
:onViewableItemsChanged viewable-ref
;;#(dispatch [:load-if-at-last %1 %2])
:style {:paddingLeft 10
:paddingRight 10}}])]]))
after wrapping with as-element, it seems that the :videos-loaded subscription inside isn’t workingI’m following the second answer in this to use onViewableItemsChange properly: https://stackoverflow.com/questions/48045696/flatlist-scrollview-error-on-any-state-change-invariant-violation-changing-on
yes, apologies. if you're passing home
in like this then it won't subscribe to your re-frame subs
basically I was trying to do in the flatlist:
:onViewableItemsChange #(dispatch […])
But this gives https://stackoverflow.com/questions/48045696/flatlist-scrollview-error-on-any-state-change-invariant-violation-changing-onso I wrapped it around useCallable
and that’s where we’re at
let's try what @U2FRKM4TW suggested with a couple modifications:
(defn home [{:keys [navigation] :as props}]
(let [on-viewable-items-change (.-current (useRef ,,,))]
(dispatch [:load-videos 1])
[safe-area-view {:backgroundColor :white :flex 1}
[:<>
(if-not @(subscribe [:videos-loaded])
,,,)]]))
(defn wrapped-home [props]
[:f> home])
the error you were seeing before about "Rendered more hooks than during the previous render" was due to having the useRef
call inside of the if
expression
hooks calls must be static across renders - you cannot put them inside loops or conditionals
Hey gals and guys, What is the easiest way to debug a component in order to understand why it gets re-rendered please? (I read https://github.com/reagent-project/reagent/blob/master/doc/WhenDoComponentsUpdate.md) This is my component:
(defn- regular-cells
[& {:keys [entity]}]
(js/console.log "regular-cells" entity)
[:div
{:on-click #(do (js/console.log "clicked")
(dispatch [:my.ns.events/clicked entity]))}
(str entity)])
When I click on the div, it has the effect of sending a PUT request to an API, then a GET to that same API which returns a new value for entity
.
Here is what I get in the logs:
regular-cells {:id 1955, :enabled false}
clicked
regular-cells {:id 1955, :enabled false}
regular-cells {:id 1955, :enabled false}
regular-cells {:id 1955, :enabled true}
I don't understand why it gets re-rendered 3 times instead of 1 after clicked
if the only param hasn't changed?If it's used as (regular-cells ...)
, then replace ()
with []
.
If it's used with []
, then it's probably because the :on-click
function get recreated on each render of regular-cells
. I don't know all the inner workings of this particular issue, but there have been numerous discussions about it.
I believe there are hooks that fix it, but I'm not sure whether using them for such a simple component would be worth it. It could also be fixed by using a cache manually, which is also more trouble than it might be worth in this particular case.
If you confirm that it's indeed the latter, you can @ lilactown - I remember him having this discussion with someone else recently.
Thank you @U2FRKM4TW, I'll check how regular-cells
and continue my investigation 🙂
I finally nailed it
I had something like this:
(into [:div]
(cond-> [[regular-cells :entity @entity]]
@show? (merge [:div "..."] [:div "..."])))
And moving the @show? ...
upper in the DOM fixed it. I'm not 100% sure why.Not sure either. But this particular code makes me squint in suspicion. The contract of merge
says that it's to be used only with maps. But you're passing it vectors. I have no clue what you want to get out of it, but it's definitely not a correct usage.
Using into
instead of merge
if for sure a better practice. It doesn't resolve the issue though (tested)
Sure, I didn't mean that it would help with the initial problem. It's just that using merge
on anything other than maps is an undefined behavior.
Oh ok, thank you for pointing that out 🙂