Hey guys I'm trying to understand a bit more of reagent. I've got the following component:
(defn c []
(let [state (r/atom false)]
(fn []
(let [edit (fn [] (reset! state true))
data (filter (fn [v] (if @state (even? v) (odd? v))) [1 2 3 4 5 6])]
[:div
(for [item data]
^{:key item} [:p item])
[:button {:on-click edit } "tap me"]]))))
The reference of state is being updated when I keep pressing the button
. But the filter
function doesn't seem to be updating.
Can someone help me further my understanding as to why this is happening?@alexander.890 I think the problem is that you’re dereferencing the state
atom inside of a lazy sequence
reagent does some magic… basically, when it executes your render function, it captures any reagent.core/atom
dereferences and tracks those to call your function again when it changes
but because it’s in a lazy sequence, it doesn’t actually get executed when your component function is called. it gets dereferenced sometime later in reagent’s machinery, when the lazy sequence is realized and turned into react elements
if it is due to the lazy sequence, you should be able to wrap your (for ,,,)
in a doall
to force the realization when executing the render function
Ah okay that makes more sense, when I moved the filter
call inside the (for [ item (filter....)]
it properly updated state.
@lilactown thank you 🙂
sure thing. I’m not sure why moving the filter inside of the for would make a difference, but to be sure, wrap it in a doall
to ensure it always gets realized while executing the render function
architecture question: i have a card game where mousing over a card will show the image in the corner of the screen. this is handled by using a channel and a go
block that changes the global r/atom app-state
, which propagates down to the "card zoom" div. This feels messy, and inhibits my ability to extract the card-view logic into a new file (cuz the main file is nearing 2k lines 😬 )
to maintain the same system, I could create a zoom-channel
namespace, move the channel to it, and then require it in both the gameboard
namespace and the newly created card-view
namespaces, but that feels like i'm missing the point
has anyone dealt with something like this?
likewise, as I'm asking questions, is this a good idiom?
(go (while true
(let [zoom (<! zoom-channel)]
(swap! app-state assoc :zoom zoom))))
is someone still using the https://github.com/ckirkendall/kioo library?
It still uses the React.createClass function, which is obsolete
I’ve see that now that function has it’s own npm package:
but does someone knows how to tell to kioo to use the function in that npm module?
@andrea.russo Create-react-class in available in cljsjs. Kioo accesses the createClass function through React global object, so you can do something like (:require ["create-react-class" :as createClass])
(set! (.-createClass js/React) createClass)
and Kioo should see the function from the package.
Tried this approach, but I get this error:
failed to load kioo.util.js TypeError: React.createClass is not a function at eval (util.cljc:56) at eval (<anonymous>) at Object.goog.globalEval (app.js:836) at Object.env.evalLoad (app.js:2224) at app.js:2786
and
failed to load sablono.interpreter.js TypeError: React.createClass is not a function
I should do the set! before the kioo library is loaded
I’m using shadow-cljs to import directly npm packages
create-react-class is imported through that
shadow-cljs has a guide on how to migrate from cljsjs: https://shadow-cljs.github.io/docs/UsersGuide.html#cljsjs
you can likely just require cljsjs.create-react-class
looks like something assumes that is available without requiring it itself
just make sure you require that before loading the kioo sources
That solves that problem! Many thanks!
Hey folks! I have been trying to use reagent with a library for rendering a Markdown Editor called reagent-mde (https://github.com/andrerpena/react-mde). I'm hitting the infamous problem of the cursor positioning inside the`textarea` element that the react-mde
library uses internally.
I looked into the "fix" for Material UI from https://github.com/reagent-project/reagent/issues/265#issuecomment-397895508 and tried to implement it. I basically forked the project, added a custom props so I could specify which textarea`` component to use, and I'm passing a custom reagent`textarea` component so that the cursor positioning works.
This fixed the cursor positioning but left me with another problem. Most of the editor functionalities (transforming text to bold, italic, etc.) depends on a
ref
to the textarea component. And, of course, when I pass a custom textarea
component, the ref points to my component instead of the textarea
node itself, and everything breaks because my component does not has the properties the textarea has. I tried making a hack so I could also give a ref
for the library, but I could not get it working.
Anyone has any idea how I could get it working, implementing a fix for the cursor positioning but still giving the library a ref to the inner textarea
component?
Here is a git repo with a minimal example:
https://github.com/vitorqb/react-mde-and-reagent-example/blob/master/src/reagent_with_mde_example/core.cljs#L9
Just
git clone <https://github.com/vitorqb/react-mde-and-reagent-example.git>
npx shadow-cljs watch app
And go to 127.0.0.1:3000
My fork of the react-mde where the textarea
component is being used is https://github.com/vitorqb/react-mde/blob/allows-customizing-textarea-component/src/components/TextArea.tsx#L320
Thanks!you’ll need to forward the ref somehow
I don’t know how reactify-component
really works
but you might try something a little different:
(def textarea-component
(-> (fn textarea [props ref]
(r/as-element [:textarea (assoc props :ref ref)]))
(react/forwardRef)))
this creates a React function component that renders a reagent :textarea
element, and forwards the ref prop to the :textarea
element
Cool, I had never heard of this forwardRef
strategy. I'll give it a try!
I’m not sure if that’s enough to fix the cursor problem tho
yeah, forwardRef is the underlying React mechanism for doing what you’re talking about: https://reactjs.org/docs/forwarding-refs.html
Cool! I'll do some experimentation see if I can get it working. Thanks!
@lilactown works like a charm! You just made my day, I was getting crazy after ~4h trying to get it working. Thanks!!!
great to hear!
in lieu of specific advice to the situation i posted earlier, anyone have "reagent architecture" tutorials or stuff? reagent's docs aren't super clear on how to structure an app
I'm having the following errors in an app with reagent figwheel-main and material-ui. I tried a lot of things and it's probably because of the versions as I was using the same stack in a previous project with previous versions of reagent, react and material-ui.
Uncaught Error: 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
The above error occurred in the <WithStyles(ForwardRef(Button))> component:
in WithStyles(ForwardRef(Button))
It looks like I should change the material-ui elements to make it compatible with Reagent. Is that right?
I see that with another react component it works, so the problem is specificaly with material-ui, but I was using it before with reagent.. I'll make a repo reproducing the problem in case someone can help me.
You can use hooks in reagent components but is a bit cumbersome. Here is an example from a personal project:
(def CardInner
(r/reactify-component
(fn []
[c/Paper "worked"])))
(def AnimatedDiv (oget animated "div"))
(defn Card
[]
(let [[props set] (useSpring (fn [] #js{:x 0 :r 0}))
x (oget props "x")
r (oget props "r")
bind (useDrag (fn [drag]
(let [down? (oget drag "down")
[mx] (oget drag "movement")]
(set #js{:x (if down? mx 0)
:r (if down? (/ mx 50) 0)}))))]
(r/create-element
AnimatedDiv
(oset! (bind) "!style" #js{:transform (interpolate #js[x r] #(str "translateX(" %1 "px) rotate(" %2 "deg)"))})
(r/create-element CardInner))))
(defn use-card []
[:div
(r/create-element Card)])
When doing this, remember to make sure the component isn't re-mounting all of the time.
I'm actually seeing that I get this error when upgrading figwheel-main from 0.2.0 to 0.2.1. I posted a question in the figwheel-main channel https://clojurians.slack.com/archives/CALJ3BFLP/p1587949472108600