Fork me on GitHub
#reagent
<
2018-03-19
>
andrewboltachev12:03:03

Hello. Did anyone have a problem with advanced compilation of type-3 components?, I have now:

(defn my-component [...]
  :componentDidMount (fn [...] (this-as this (.myMethod this)))
  :myMethod (fn [...] ...do something...)
...)
And Google Closure Compiler (with options :pseudo-names and :pretty-print set to true) reports me an error: this.$myMethod$ is not a function

andrewboltachev12:03:21

(i.e. JavaScript compiled by it reports)

juhoteperi12:03:13

@andrewboltachev I think the name created by create-class won't be optimized, but the name from .myMethod call will be optimized so this won't work

andrewboltachev12:03:27

yeah, it seems like so

juhoteperi12:03:34

((gobj/get this "myMethod") ...) might work

juhoteperi12:03:49

Or other similar ways to get the method dynamically from the object, so the name is not optmized

andrewboltachev12:03:21

aha, and gobj itself has to be :required?

andrewboltachev12:03:37

aha. great, would try this!

juhoteperi12:03:43

It is the recommended way to access JS objects in Cljs

juhoteperi12:03:21

(Reagent implementation itself uses aget/aset currently, but those should only be used with JS arrays...)

andrewboltachev12:03:06

Have suchlike problems accessing SVG objects as well: .getBBox method gots compiled away

andrewboltachev12:03:21

So, :advanced definitely comeas at a cost

andrewboltachev12:03:24

@juhoteperi great, should it go to src/externs?

juhoteperi12:03:42

Path doesn't matter, you need to add it to :compiler-options :externs list

andrewboltachev12:03:15

aha, so then like :externs ["src/externs/svg.js"]

juhoteperi12:03:18

It should probably be packaged into Cljsjs, as extern only package, I though it was done already but doesn't seem like it

borkdude13:03:19

Is it possible via some trick to get the name of a parent component? e.g. in a React lifecycle method?

pesterhazy14:03:33

@andrewboltachev wait why are you doing it this way?

pesterhazy14:03:39

no need to mess with this-as

andrewboltachev16:03:41

uhm, indeed, thanks for pointing out!

pesterhazy14:03:07

... I guess this has nothing to do with your question 🙂

pesterhazy14:03:11

Juho already answered the actual question

mhuebert14:03:07

if you have externs inference on, you could also add a type annotation to the component. with shadow-cljs,

:component-will-mount (fn [^js this] (.mymethod this ...))

mhuebert14:03:28

that would prevent myMethod from being renamed by the compiler

pesterhazy14:03:30

.getBBox is special I imagine because more common DOM methods like .focus are blacklisted in Google Closure and won't be minified (I think...)

pesterhazy14:03:34

@mhuebert interesting, does this work with cljsbuild or figwheel as well?

mhuebert14:03:34

i don’t know, it would be worth trying. externs inference itself is not specific to shadow-cljs

mhuebert14:03:35

however I think @thheller did quite a bit of work to make externs inference in shadow-cljs work (a) more often and (b) without extra config, so I am not sure how it compares to the cljsbuild experience

mhuebert14:03:49

I use it all the time now though. ’tis easy to add ^js in front of whatever thing should be treated as external, = few & easy to debug :advanced problems

pesterhazy14:03:29

the page you linked to doesn't mention ^js hinting, only specifying a class like ^js/Foo.Bar

athomasoriginal14:03:15

How does one go about specing a function in reagent which returns hiccup? I know these are just vectors, but I am curious if one would expect something more than :ret vector??

pesterhazy14:03:46

the first element must be a function or a keyword

thheller14:03:27

@pesterhazy the ^js hint without a class reference is specific to shadow-cljs. I feel the class should be optional and it doesn't matter anyways. see https://code.thheller.com/blog/shadow-cljs/2017/11/06/improved-externs-inference.html

thheller14:03:05

CLJS by default wil respect ^js but I believe it won't generate externs for them

thheller14:03:18

I want to do an official proposal for this at some point but didn't get around to it yet

pesterhazy14:03:56

seems reasonable to me

pesterhazy14:03:16

anything that reduces the pain of adv compilation is a win in my book

camachom20:03:38

does reagent provide anyway of making state available to helper functions? In React, you can simply call this.state since its part of a class. In Reagent, I find myself passing state as an argument way too often since I don't want global variables.

justinlee20:03:53

@mcama200 whenever i find that i want to reach for a method, i replace it with a function defined in a let block

justinlee20:03:03

then you can just close over the state you need

camachom20:03:16

thanks for your help. would you have any examples I could see? So the bulk of your functionality would be defined in the let statement?

justinlee20:03:54

yea that’s how I do it.

(defn my-comp
  [args]
  (let [state (reagent/atom nil)
        method-1 (fn [] (swap! state ...))]
    (fn [args]
       [:div "whatever"])))    

camachom20:03:59

interesting. seems like a viable option

justinlee20:03:54

the let blocks can get huge but so can class definitions. the main reason why people don’t like this style is because you can’t test the functions individually

gadfly36120:03:31

@mcama200 I pass my app-state ratom around as the first argument pretty much everywhere .. a great alternative is to use re-frame tho (it solves this headache)

camachom20:03:20

yeah that was my understanding as well. Just wanted to see if Reagent provided any mechanism without reaching out to a data-management lib.

justinlee20:03:07

i’d say the “reagent” way is to use functions and closures. the design principle of the library seems very focused on enabling you to write websites using normal functions

justinlee20:03:47

@gadfly361 what is the basic re-frame solution in a nutshell?

gadfly36120:03:36

@lee.justin.m basically re-frame closes over app-db implicitly, so when you write event handlers, you always have access to the entire world of state (so you don't have to pass it in as an argument anymore) .. it's just a convenience (that i think has more positive than negatives)

gadfly36120:03:04

Also I guess saying closes over is kind of a lie .. i think app-db is injected as a coeffect, but basically works the same way

mikethompson20:03:33

@lee.justin.m @gadfly361 if you want it in a nutshell read "What Are They?" in this doc. Just a few paragraphs: https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md#what-are-they

mikethompson20:03:08

At moments like this I point towards this re-frame FAQ entry: https://github.com/Day8/re-frame/blob/master/docs/FAQs/DoINeedReFrame.md