I just realized that something that was simple in js, I don't know how to do it in clojurescript
anyone uses shadow-cljs? is there a way to hack the dependencies so that helix when requires react and react-dom, I can instead specify a different version for it to use? đ
I want to use helix with https://reactjs.org/docs/concurrent-mode-adoption.html I am not very happy about this separation of versions, but what to do
With shadow-cljs, you just use npm for all that.
Helix (from what I can see) doesnât bring that in for you
"all that", "that", I find it hard to understand what "that" exactly is in each case : ) Could you elaborate please?
the thing is that I have 3 separate version of react installed
so it would be nice if I could tell helix which one to use
Helix doesnât come into it - itâs shadow CLJS which uses whatever is in node_modules
of course it does, it requires react to be installed under the name react
it's another thing that shadow-cljs provides this under the name of react, but if it wouldn't be a predefined name, it would be nicer, so I could have whatever version used
since otherwise I would have to constantly update the build config for something that is business logic in this case, which version I am demoing
and I hate the semantic web more and more
it's prescriptivist through and through
so, I am getting errors with the experimental build, and I am not sure why. Has anyone tried to use helix with react@experimental before?
yes, I have
as for using helix with a package of a different name than React, Iâm not sure how to support that
if you post the error youâre seeing I might be able to help you đ
most errors are due to installing mismatching versions - e.g. you install react@experimental
but donât install react-dom@experimental
and react-refresh@experimental
(if youâre using react-refresh)
FWIW install the experimental versions should just work - thereâs no additional config required. if you for some reason want multiple versions of React on the same web page at the same time, I donât know how to do that
You can alias package names with shadow-cljs, e,g., I use it for react-native-web:
:js-options {:resolve {"react-native" {:target :npm
:require "react-native-web"}}}
not using refresh I think, but will check
@alidcastano that does work but it works for all packages overall the same way, can't specifically resolve different versions for different dependencies
one thing I would like to ask a bit of help before I go back to the experimental build, is how to use the progress channel of cljs-http with helix. Is there an idiomatic way to read in a use-effect or something from the channel?
basically, writing while(true) seems weird, even in a use-effect
I am not sure if it will work đ
@ashnur i donât think youâd ever want two* versions of react running at same time. specially with hooks, that will cause nasty errors
just set the necessary alias per build
if you need a useEffect to run every time just donât pass dependencies array as second argument
don't tell me what I want
: )
That's not an answer to my specific question. I get how react works, I have trouble using cljs http channels
also, I don't want to use different react versions TOGETHER, I want to use them in the same app. That's not together. : ) but I have since got help in #shadow-cljs that it's better to have separated builds, so I completely given up on that idea, I will not complicate my life by fighting the tooling. (It's worth mentioning though how limiting is when people assume they know what others want or might or might not want : D)
there are several ways you could use core.async channels with hooks
depending on your use case
Iâd have to think more about it. for one-shot requests you might be able to do:
(let [[response set-response] (hooks/use-state nil)]
(hooks/use-effect
:once
(go (-> (<! (http/get "api"))
(set-response))))
,,,)
ah, the progress channel, sorry
đ
I am using take! and put! from onChange and onClick at the moment
simpler than setting up a go loop, but probably not what I should use for the progress events
(defhook use-take
[channel on-take]
(let [cancel-signal (hooks/use-ref false)]
(hooks/use-effect
[channel on-take]
(go-loop []
(if-not @cancel-signal
(do (on-take (<! channel))
(recur))
(reset! cancel-signal false)))
#(reset! cancel-signal true))))
something like that
wow, thanks, that's very detailed!
the last line is the return function to run on unmount in react?
trying to figure out where mounted? will play a picture
in any case, this is enough to solve it, thanks again
ah sorry, I forgot to remove mounted?
it was part of an earlier draft
yeah, in use-effect
you can return a function that runs when the dependencies change, or the component is unmounted
itâs a âcleanupâ function for the effect
note I havenât tested that at all đ so might not quite work. but itâs the general idea
it's very useful, i was looking for some proper way to loop only when actually something happens, I just need to read the docs about these functions
I almost never use loops, just lazy seqs
Ok, so I don't get the else clause for the if-not. That should only ever be true after the hook was unmounted, but at that point I just want it to be garbage collected, a new element mounted will use a new hook anyway. In fact, what I would rather do somewhere is to check if the channel is closed and escape the loop then
yeah, the else clause is there to cleanup when either the channel changes, the on-take
function changes, or the component unmounts
if it hits that branch, then itâs because the effect has run the cleanup function
but the go-loop
will still be running, which is why we check for the cancel-signal
and if itâs true
, donât recur
for example, if we naively did
(go-loop []
(do (on-take (<! channel))
(recur)))
then even once the effect cleaned up, it would still be running the go-loop and it wouldnât be garbage collectedI don't understand what it achieves to set the cancel-signal back to it's initial value
maybe it's a typo and should be true? but then it would never reach that clause
https://gist.github.com/ashnur/c336b998fbc5d7c7580aa52fe9e827f7 this is how I would expect it to work naively đ
Iâm not completely sure if I did that right
my thinking was that, if you pass in a new on-take
function, you want to stop your go-loop
and start another go-loop
using the new function
I know exactly the feeling : )
so in that case, you want to have your current go-loop
see the cancel-signal, and then reset it so the new one will start
but I might have done it wrong
calling the use-take hook a second time should create a new loop entirely imho, it's a new scope, new context, new bindings
itâs not calling it a second time
with a different argument should mean a different call?
think about like if you take a function as a prop, and the function changes
or if it depends on some state
(defnc my-component
[]
(let [[state set-state] (hooks/use-state "")
on-take (fn [chan-value]
(println "current state is:" state "and channel value is:" chan-value))]
(use-take some-channel on-take)))
I think this topic deserves more examination : D I tried to find clojurescript + react/hooks + channels examples online but I only found your hooks/cljs examples, nothing much else.