Fork me on GitHub
#reagent
<
2022-01-24
>
Rodrigo Mantica13:01:15

I’m trying to embed cljs react components in an existing javascript codebase. I’m using shadow-cljs to compile my cljs to js and using reagent with /reactify-component to produce components. My JSX is being picked up, but my button :on-click is not being called in the js ecosystem

Rodrigo Mantica13:01:00

Any insight on how to embed reagent in a native react js ecosystem would be greatly appreciated

p-himik13:01:57

Hard to say without seeing the actual code. But just in case - do you compile both JS and CLJS using shadow-cljs? If not, how do you make sure that you have only a single copy of React in your app? Because by default, if you just build CLJS then the resulting JS bundle will have a copy of React on its own.

Rodrigo Mantica13:01:46

That’s likely my problem. I have an existing next js app with its own internal webpack setup. We’re seeing if an incremental migration to cljs is possible by exporting js files from our shadow-cljs setup

Rodrigo Mantica13:01:09

Trying simple hello world examples, but my button event handlers aren’t working in the javascript environment

juhoteperi14:01:00

Are you using :target :browser or other Shadow-CLJS target? Check if the output file contains copy of React. You should be able to configure Shadow-CLJS output to use React from the webpack bundle with js-provider option: https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider Or if you are already using :target :npm-module the :js-provider :require should be the default already and React shouldn't be included in the output. Haven't tried this setup.

juhoteperi14:01:13

Or if your shadow-cljs output isn't processed by webpack, you could use :resolve to tell shadow-cljs to get React object from a global variable: https://shadow-cljs.github.io/docs/UsersGuide.html#js-resolve (then you also need to ensure webpack will publish React in the global var)

juhoteperi14:01:07

And problems with event handlers does sound like something that can be caused by having multiple React versions loaded in the page, due to how React implements event handling.

Rodrigo Mantica14:01:33

@U061V0GG2 I’m using :npm-module target

Rodrigo Mantica14:01:21

I’ll check if I have a react copy. All I see is a shimmed one: require("./shadow.js.shim.module$react.js");

thheller17:01:45

:npm-module is the way to go here and :resolve or :js-provider doesn't apply

thheller17:01:56

how do you use the CLJS code from JS?

Rodrigo Mantica19:01:53

@U05224H0W I’m running shadow-cljs watch app with the following config:

{:source-paths
 ["src"]

 :dependencies
 [[reagent "1.1.0"]]


 :builds
 {:app {:target :npm-module
        :output-dir "../frontend/cljs"
        :asset-path "/js"
        :devtools {:after-load app/main}
        :modules {:main {:init-fn app/main}}}}}

Rodrigo Mantica19:01:38

My cljs source looks like so:

(ns app
  (:require [react :as react]
            [reagent.core :as r]
            [reagent.dom :as rd]))

(defn app [props]
  (let [[incs set-incs] (react/useState 0)
        [decs set-decs] (react/useState 0)
        total (+ incs decs)]
    (react/useEffect #(print (str "total " total)) #js[array incs decs])
    [:div
     [:p "props: " (prn-str props)]
     [:p "total: " total]
     [:p "increments: " incs]
     [:p "decrements: " decs]
     [:button {:on-click #(set-incs inc)} "Increment"]
     [:button {:on-click #(set-decs dec)} "Dec"]]))

(defn func-comp [props] [:f> app props])
(def react-comp (r/reactify-component func-comp))

Rodrigo Mantica19:01:14

Then in javascript react files, I import the reactified component like so: import { react_comp as ReactComponent } from 'cljs/app'

Rodrigo Mantica19:01:39

It renders the JSX correctly and logs the use effect print statement, but the button event handlers are not firing

Rodrigo Mantica19:01:10

Using the app func directly in my JSX seems to behave the same way

thheller21:01:28

{:on-click #(set-incs inc)} react/useState is an actual set not a swap!. so you setting it to the inc function unless I'm missing something?

thheller21:01:32

should likely be {:on-click #(set-incs (inc incs))}?

thheller22:01:42

I would assume that the on-click actually fires but then fails one re-render since (+ incs decs) will fail when incs is the inc function?

juhoteperi22:01:44

If setState update if is given a function, React will call that with the current value etc. so it works as both reset! and swap!

thheller22:01:20

oh? ah didn't know that

thheller22:01:23

nevermind then 😛

Rodrigo Mantica05:01:26

Event handlers were working fine the whole time… I was preventing click events with css essentially :face_palm: