reagent

Aron Gabor 2023-10-03T08:13:22.533159Z

hi, how much should I expect reagent to work with react 18.2 I am having the classical state is updated but component doesn't rerender problem and I have no idea why, from other examples online it looks like i am doing the same thing, but I've found 2 year old github issues unsolved with the same problem, so I am thinking, it's probably best to abandon ship?

rolt 2023-10-03T08:58:18.482319Z

I'm using react 18.2 with reagent and haven't encountered any issues, are you using any specific react features ?

Aron Gabor 2023-10-03T09:00:59.938109Z

hmm, I didn't think there will be an answer, but I am happy there is. give me a minute to bring alive one of my earliest minimal examples that I was struggling with

Stef Coetzee 2023-10-03T11:02:47.601669Z

I haven't had issues with React 18. Example setup below (excerpts only, for brevity):

# Main CLJS app file

(ns client.app.main
  (:require [reagent.core :as r]
            [reagent.dom.client :as rdc]))

(defonce app-root
  (rdc/create-root (.getElementById js/document "app")))

(def functional-compiler
  (r/create-compiler {:functional-components true}))

(defn render []
  (rdc/render app-root
              <add your app here>
              functional-compiler))

(defn ^:dev/after-load start []
  (js/console.log "Start")
  (render))

(defn ^:dev/export init []
  (js/console.log "Initialize")
  (start))

(defn ^:dev/before-load stop []
  (js/console.log "Stop"))
I typically add the start, init, and stop functions early in development to help me slot functionality in if need be at a later stage.
# package.json

{
  "devDependencies": {
    "shadow-cljs": "^2.25.2",
  },
  "dependencies": {
    "react": "18.2.0",
    "react-dom": "18.2.0"
  }
}

Aron Gabor 2023-10-03T11:42:38.326839Z

sorry, this took longer than expected, actual work intervened, this example doesn't work for me at all, the console log is shown, so the render supposedly runs, but there is no visual update for the counter's value:

(ns app.browser
  (:require
   [reagent.core :as r]
   [reagent.dom.client :as rdomc]
   ["react" :as react]))

(def !counter (r/atom 0))

(defonce react-root
  (rdomc/create-root (js/document.getElementById "app")))

(defn comp1
  []                                
  [:button  {:class "button-class"
          :on-click  #(swap! !counter inc)} 
   "+"])

(defn app []
  (js/console.log @!counter)
  [:div.container
   (str @!counter)
   [comp1]])

(defn ^:dev/after-load start []
  (rdomc/render react-root [:> react/StrictMode {} [:f> app]]))

(defn init []
  (js/console.log "init")
  (start))

(defn ^:dev/before-load stop []
  (js/console.log "stop"))

rolt 2023-10-03T12:24:50.831669Z

[app] vs [:f> app]

rolt 2023-10-03T12:30:47.764859Z

app is already a reagent component so I don't think :f> will work

Stef Coetzee 2023-10-03T12:52:00.482799Z

This works for me:

(ns app.main
  (:require [reagent.core :as r]
            [reagent.dom.client :as rdc]))

(def !counter (r/atom 0))

(defonce app-root
  (rdc/create-root (.getElementById js/document "app")))

(def functional-compiler
  (r/create-compiler {:functional-components true}))

;; Components

(defn increment-counter []
  [:button
   {:on-click (fn [] (swap! !counter inc))}
   "+"])

(defn app []
  (js/console.log (str "Counter: " @!counter))
  [:div
   [:div
    (str "Counter: " @!counter)]
   [:div
    [increment-counter]]])

(defn render []
  (rdc/render app-root
              [app]
              functional-compiler))

;; ---

(defn ^:dev/after-load start []
  (js/console.log "Start")
  (render))

(defn ^:dev/export init []
  (js/console.log "Initialize")
  (start))

(defn ^:dev/before-load stop []
  (js/console.log "Stop"))

Stef Coetzee 2023-10-03T12:53:56.564279Z

I found the docs on the compiler (covers functional component implementation) quite helpful. https://github.com/reagent-project/reagent/blob/master/doc/ReagentCompiler.md#reagent-compiler

Aron Gabor 2023-10-03T12:54:32.457499Z

:f> was necessary originally because the actual problem came up when I was integrating cytoscape via an effect hook

rolt 2023-10-03T12:55:24.763029Z

you should pass a react function component to :f>, not a reagent component

Aron Gabor 2023-10-03T12:55:30.528179Z

But I can confirm that removing it makes the button work

rolt 2023-10-03T12:55:52.687939Z

the reagent component will be either a function component or a class component depending on the reagent compiler used

Aron Gabor 2023-10-03T12:56:24.263229Z

I will try this alternate solution to use functional components

Aron Gabor 2023-10-03T13:08:36.112909Z

well, the demo I constructed works without the :f> and my useeffect also works with the functional-compiler, but the state update -> component render still doesn't happen, even though I removed all :f>

Aron Gabor 2023-10-03T13:08:58.947689Z

is there some sure fire way to debug/troubleshoot this phenomenon?

Aron Gabor 2023-10-03T13:10:27.636789Z

looks to me that when I call my hook, everything else in the component is ignored afterwards

Aron Gabor 2023-10-03T13:13:44.694359Z

(def data (r/atom nil))

(defn setup-cyto [{:keys [cs config]}]
  (cs config))

(defn use-cytoscape [element config els]
  (react/useEffect
   (fn []
     (when (some? @element)
       (let [js-els (clj->js  els)
             cy (setup-cyto {:cs cs
                             :config (config element js-els)})]
         (-> cy
             .nodes
             (.on "click" #(reset! !koala (.id (.-target %)))))
         (reset! data cy)
         (.resize cy)
         (.fit cy)
         #(.destroy cy)))
     js/undefined)))

Aron Gabor 2023-10-03T13:13:55.549169Z

just the hook for completeness

rolt 2023-10-03T13:19:42.651339Z

I use react hooks without issues, but have never used useEffect (defn app [] [:f> use-cytospace]]) doesn't work ?

rolt 2023-10-03T13:23:19.387599Z

i'm just not sure you can use the ratom inside the useEffect function, and still have reactivity on the ratom change

👀 1
rolt 2023-10-03T13:24:24.041659Z

but maybe just deref-ing the ratom in use-cytospace (outside useEffect) would work ? it's a bit of a hack 😕

Aron Gabor 2023-10-03T13:26:31.229659Z

what do you mean never used useEffect? how do you integrate third party tools then?

Aron Gabor 2023-10-03T13:29:01.051599Z

did you mean this line (.on "click" #(reset! !koala (.id (.-target %)))))

rolt 2023-10-03T13:40:36.819039Z

i'm not sure i follow, you were saying the component doesn't get re-rendered. What i'm saying is that I don't think use-cytoscape will be re-rendered if element changes here (unless you deref element after useEffect (defn use-cytoscape [] (react/useEffect ...) @element [:<>])

rolt 2023-10-03T13:42:35.665309Z

or is it when data changes ? I don't see data's value being used anywhere

Aron Gabor 2023-10-03T13:48:32.825899Z

that's it

Aron Gabor 2023-10-03T13:48:45.685749Z

will try in a moment, just work wouldn't be in the way

Aron Gabor 2023-10-03T14:13:07.500139Z

I am afraid no amount of derefing changes this. I think I am doing something wrong if it works for you, but I don't know what to look at. I have a bunch of console logs and only the ones that are before the use-cytoscape hook run more than once, all the rest runs at the first click but not again

Aron Gabor 2023-10-03T14:13:18.775849Z

i put derefs everywhere 😄

rolt 2023-10-03T14:23:09.136789Z

(def x (reagent/atom 0))

(defn a
  []
  [:button
   {:onClick #(swap! x inc)}
   "click me"])

(defn b
  []
  (react/useEffect
   (fn [] (println "clicked !" @x) js/undefined))
  @x
  [:<>])

(defn app []
  [:<>
   [a]
   [:f> b]])

rolt 2023-10-03T14:24:38.975919Z

with the following, I do get the println everytime I click the button in a

Aron Gabor 2023-10-03T14:32:30.410309Z

the console.log appears for me too, but the value doesn't change

Aron Gabor 2023-10-03T14:32:57.934449Z

probably your code would though, as earlier the demo was working for me too without the :f>

rolt 2023-10-03T14:33:47.055589Z

which value ?

Aron Gabor 2023-10-03T14:34:21.877769Z

the one being reset by the hook.

rolt 2023-10-03T14:35:57.637769Z

data ?

rolt 2023-10-03T14:36:32.931789Z

are you sure @element is not nil/false ?

Aron Gabor 2023-10-03T14:38:55.210239Z

no, !koala 🙂

Aron Gabor 2023-10-03T14:39:32.248819Z

and I can check the element, but I would guess right now that it's not empty, the cytoscape graph being visible in it

rolt 2023-10-03T14:47:58.169309Z

ok so it doesn't really have anything to do with useEffect that line is a bit too specific to your lib so I can't help

Aron Gabor 2023-10-03T15:03:28.723559Z

thanks, you already helped immensely, at least i can be confident that this should work