reagent

A minimalistic ClojureScript interface to React.js http://reagent-project.github.io/
andrewboltachev 2020-04-04T15:23:19.053900Z

Hello. When using reagent components (say, I'm using the form with r/create-class), how to bind custom event handlers (e.g. I have :clickHandler (fn [event] (this-as t t)) and want this to be the element here, not Window)? Should I do (.bind ...) on :component-did-mount or in some other place?

p-himik 2020-04-04T15:28:16.054100Z

Don't know what the rest of your code looks like, but if possible I would use ref instead of this.

lilactown 2020-04-04T15:29:07.054300Z

what do you want to do in your click handler that requires this?

juhoteperi 2020-04-04T16:06:58.054500Z

Usually there is no reason to make the event handlers class methods with Reagent, like is common in React. Just create handler fn in let binding. Anyway, the first parameter of class methods is going to be the component instance. Then you can ask the dom node from that. (This doesn't work for custom methods, just built-in methods)

juhoteperi 2020-04-04T16:10:40.054800Z

And using ref instead of checking component instance for dom node is highly recommended by React now.

p-himik 2020-04-04T16:12:16.055Z

Yeah, was just about to quote it: "If you have absolutely no control over the child component implementation, your last option is to use findDOMNode(), but it is discouraged and deprecated in StrictMode [in favor of refs]."

andrewboltachev 2020-04-04T16:38:00.055300Z

@lilactown read props

andrewboltachev 2020-04-04T16:40:21.055500Z

@lilactown i.e. when a menu isn't open, then don't close it. I thought that as a way to avoid menu instantly closing on my click event

andrewboltachev 2020-04-04T16:41:29.055700Z

@juhoteperi @p-himik so that should be function refs right? I.e. not React.createRef() but sth more old?

lilactown 2020-04-04T16:42:07.055900Z

is there a reason you’re use r/create-class?

p-himik 2020-04-04T16:42:10.056100Z

You can use createRef if it would work in your case. Hard to say anything based on a general description.

lilactown 2020-04-04T16:42:23.056300Z

I don’t think you want to use refs here

andrewboltachev 2020-04-04T16:44:57.056500Z

well. what I want is that when I click outside of menu it closes (also possibly with CSSTransition from react-transition-group)

andrewboltachev 2020-04-04T16:45:37.056700Z

and lifecycle methods I need to add/remove click event listener on whole document element

lilactown 2020-04-04T16:45:57.057Z

gotcha. that makes sense

lilactown 2020-04-04T16:46:31.057200Z

like juhoteperi said, you should create the handler in a let binding before you create the class. then pass in the props you need to give to the click handler in the reagent-render function

(defn my-component
  (let [click-handler (fn [event thing1 thing2]
                        ;; do stuff with event and thing1 and thing2
                        )]
    (r/create-class
      {:reagent-render
       (fn [thing1 thing2]
         [:button {:on-click #(click-handler % thing1 thing2)} "click me"])})))

andrewboltachev 2020-04-04T16:47:34.057500Z

well, but that's a click handler for whole document, not for a button

lilactown 2020-04-04T16:48:03.057700Z

I’m talking about your original question, about how to access this inside an event handler to get props

andrewboltachev 2020-04-04T16:48:51.057900Z

thanks for suggestion, but yes, I wanted to get props inside of a handler for click on document

lilactown 2020-04-04T16:49:04.058100Z

I see

lilactown 2020-04-04T16:49:37.058300Z

component-did-mount and component-will-unmount both receive this as an argument

andrewboltachev 2020-04-04T16:49:52.058500Z

yes, I tried that, but then it somehow didn't work

andrewboltachev 2020-04-04T16:49:55.058700Z

i.e.

andrewboltachev 2020-04-04T16:51:10.058900Z

`(js/document.addEventListener "click" (.bind (aget this "clickHandler") this))`

andrewboltachev 2020-04-04T16:51:49.059100Z

and clickHandler still received event as first arg, and Window as this

andrewboltachev 2020-04-04T16:52:15.059300Z

(the way to get this in a 1st place is (this-as t t))

lilactown 2020-04-04T16:54:03.059500Z

lifecycle handlers inside r/create-class get passed this as the first argument

andrewboltachev 2020-04-04T16:54:15.059700Z

yes

andrewboltachev 2020-04-04T16:54:23.059900Z

that's how I got it

andrewboltachev 2020-04-04T16:54:38.060100Z

(js/document.addEventListener
"click"
(.bind (aget this "clickHandler") this))

andrewboltachev 2020-04-04T16:54:57.060300Z

this code is inside of my :component-did-mount

lilactown 2020-04-04T16:55:03.060500Z

sorry, I was confused by what you said using this-as. you mean you’re using this-as inside the clickHandler

andrewboltachev 2020-04-04T16:55:27.060700Z

yes, I did use this-as in a clickHandler

lilactown 2020-04-04T16:57:21.060900Z

(let [click-handler (fn [component event]
                      (let [props (r/props component)]
                        ,,,))]
  (r/create-class
   {:component-did-mount
    (fn [this]
      (let [bound-click-handler #(click-handler this %)]
        (set! (.-clickHandler this) bound-click-handler)
        (js/document.addEventListener
         "click"
         bound-click-handler)))
     :component-will-unmount
     (fn [this]
       (js/document.removeEventListener
        "click"
        (.-clickHandler this)))
     ,,,}))

andrewboltachev 2020-04-04T16:58:35.061200Z

let's see

andrewboltachev 2020-04-04T17:02:01.061400Z

yes, that works!

andrewboltachev 2020-04-04T17:02:42.061600Z

perhaps the last thing would be remove'ing the correct function

andrewboltachev 2020-04-04T17:03:04.061800Z

i.e. wrapped one

lilactown 2020-04-04T17:03:30.062100Z

it should be removing the correct one

lilactown 2020-04-04T17:03:45.062300Z

that’s why I (set! (.-clickHandler this) bound-click-handler)

andrewboltachev 2020-04-04T17:03:53.062500Z

aha

lilactown 2020-04-04T17:04:07.062700Z

and then remove (.-clickHandler this) in component-will-unmount

andrewboltachev 2020-04-04T17:05:36.062900Z

yes sure! so the only "mystery" here is why (.bind ...) didn't work

lilactown 2020-04-04T17:06:58.063100Z

I’m not sure, I’d have to see the rest of the code you had. this can get quirky when mixing react/reagent/JS code

andrewboltachev 2020-04-04T17:07:41.063300Z

ok good to know. thanks for help @lilactown!

andrewboltachev 2020-04-04T17:11:38.063500Z

FYI what I wanted to achieve is mostly this: https://blog.campvanilla.com/reactjs-dropdown-menus-b6e06ae3a8fe

andrewboltachev 2020-04-04T17:11:53.063800Z

(but I think I'll also add transitions)

2020-04-04T21:03:40.064500Z

i'm a react developer, and i'm just starting to dip my feet into the world of clojure

2020-04-04T21:03:56.065Z

how is the interop between JS/React libs and cljs-specific libs?

2020-04-04T21:04:31.065500Z

is there a preferred approach between using clojure-specific libs vs js-specific libs to solve a given problem?

2020-04-04T21:05:17.066500Z

routing's an example - I know and like react-router. does it make sense to figure out how to use it in my reagent project, or is it better to come at it from the direction of clojure (e.g. using reitit and accountant)

lilactown 2020-04-04T21:16:38.067200Z

interop can be a bit difficult. a lot of people opt for something that controls routing outside of react, like reitit and accountant

2020-04-04T21:31:01.068100Z

got it. i guess i'll bias towards a clojure-forward approach for the meantime.