Fork me on GitHub
#reagent
<
2020-04-23
>
Alex01:04:28

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?

lilactown01:04:39

@alexander.890 I think the problem is that you’re dereferencing the state atom inside of a lazy sequence

lilactown01:04:34

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

lilactown01:04:11

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

lilactown01:04:13

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

Alex01:04:32

Ah okay that makes more sense, when I moved the filter call inside the (for [ item (filter....)] it properly updated state.

Alex01:04:46

@lilactown thank you 🙂

lilactown01:04:22

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

👍 4
Noah Bogart14:04:57

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 😬 )

Noah Bogart14:04:49

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

Noah Bogart14:04:14

has anyone dealt with something like this?

Noah Bogart14:04:42

likewise, as I'm asking questions, is this a good idiom?

(go (while true
      (let [zoom (<! zoom-channel)]
        (swap! app-state assoc :zoom zoom))))

Andrea Russo17:04:38

It still uses the React.createClass function, which is obsolete

Andrea Russo17:04:57

I’ve see that now that function has it’s own npm package:

Andrea Russo17:04:48

but does someone knows how to tell to kioo to use the function in that npm module?

juhoteperi17:04:11

@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.

Andrea Russo17:04:13

Tried this approach, but I get this error:

Andrea Russo17:04:13

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

Andrea Russo17:04:37

failed to load sablono.interpreter.js TypeError: React.createClass is not a function

Andrea Russo17:04:00

I should do the set! before the kioo library is loaded

Andrea Russo17:04:37

I’m using shadow-cljs to import directly npm packages

Andrea Russo17:04:49

create-react-class is imported through that

lilactown17:04:43

shadow-cljs has a guide on how to migrate from cljsjs: https://shadow-cljs.github.io/docs/UsersGuide.html#cljsjs

thheller17:04:25

you can likely just require cljsjs.create-react-class

thheller17:04:52

looks like something assumes that is available without requiring it itself

thheller17:04:18

just make sure you require that before loading the kioo sources

Andrea Russo09:04:55

That solves that problem! Many thanks!

Vitor Barbosa18:04:11

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 
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!

lilactown18:04:39

you’ll need to forward the ref somehow

lilactown18:04:50

I don’t know how reactify-component really works

lilactown18:04:01

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)))

lilactown18:04:00

this creates a React function component that renders a reagent :textarea element, and forwards the ref prop to the :textarea element

👍 4
Vitor Barbosa18:04:51

Cool, I had never heard of this forwardRef strategy. I'll give it a try!

lilactown18:04:02

I’m not sure if that’s enough to fix the cursor problem tho

lilactown18:04:22

yeah, forwardRef is the underlying React mechanism for doing what you’re talking about: https://reactjs.org/docs/forwarding-refs.html

Vitor Barbosa18:04:16

Cool! I'll do some experimentation see if I can get it working. Thanks!

Vitor Barbosa18:04:44

@lilactown works like a charm! You just made my day, I was getting crazy after ~4h trying to get it working. Thanks!!!

lilactown18:04:59

great to hear!

Noah Bogart19:04:13

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

Jp Soares20:04:59

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))

arttuka06:04:53

that doc has an example on how to work around it

Jp Soares13:04:14

It looks like I should change the material-ui elements to make it compatible with Reagent. Is that right?

Jp Soares14:04:14

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.

Jp Soares15:04:01

This is a repo reproducing my problem https://github.com/JpOnline/t1-error Am I missing a way to wrap the component so it works?

pcj18:04:49

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)])

pcj18:04:37

When doing this, remember to make sure the component isn't re-mounting all of the time.

Jp Soares19:04:37

I finally fixed it downgrading versions based in the configuration of a previous project I have. https://github.com/JpOnline/t1-error/commit/f4bdf2271b70629c3d072e01e01812fe4379cf5d I'm seeing a lot of people explaining how to use react hooks in reagent, but I don't think it's exactly my problem, I just want to use the material-ui package, I don't need the hooks because I can manage state with re-frame or rAtom . So my question is what is the breaking change that is causing the error? React didn't have hooks in this specific version? I should keep using this versions to avoid the error?

Jp Soares01:04:50

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