Fork me on GitHub
#reagent
<
2017-09-10
>
mrchance15:09:37

Hi, I am using figwheel from cider, using piggyback. The template is reagent-figwheel. It all worked well, but now, when I autoreload some new code, I get

core.cljs:270 Uncaught Error: No protocol method IDeref.-deref defined for type cljs.core/LazySeq: ({:file "resources/public/js/dev/tool/state.js", :namespace "tool.state", :type :namespace, :loaded-file true} {:type :namespace, :namespace "tool.core", :loaded-file true})
and this list appears in a place where my state atom should be. When I reload the page in the browser, it works again Oo Any idea what might be causing this?

reefersleep15:09:24

My initial guess is that some of your code is re-deffing the symbol that your state-atom was previously bound to…

reefersleep15:09:44

Do you have your code on github, @mrchance ?

mrchance15:09:44

unfortunately no, it's a work project... I could make a gist with some parts of the setup?

reefersleep15:09:24

I guess that’d help, but without the entire code base, the error could always be occurring elsewhere 😄

reefersleep15:09:45

maybe try to reduce your code base until the error doesn’t occur, then re-introduce functionality until it does

mrchance16:09:06

Ok, but basically I should check for other code that might redefine the app-state symbol

mrchance16:09:31

But how does figwheel related information end up there? That's pretty surprising to me

reefersleep16:09:48

I think that’s the most obvious answer, yeah

reefersleep16:09:08

good question

reefersleep16:09:12

what’s the symbol name?

mrchance16:09:42

app-state, or state/app-state

reefersleep16:09:46

maybe just try changing the state atom’s symbol name where it’s defed or defonceed and see if it helps?

mrchance16:09:14

ok, will try

reefersleep16:09:14

that could save you the hunt for the re-def (if it turns out that it doesn’t help)

reefersleep16:09:46

ah, but of course you’d have to make your change a refactor in order to ensure that references to the state atom are also changed, or else your app will (I’m guessing) stop working entirely

reefersleep16:09:20

and if you’re using an automated refactor of some kind, it might be that you’ll also be changing the name where in the re-def (if there is one such)

mrchance16:09:38

No, it's fine, early days, not many references

reefersleep16:09:44

also, do you know the difference between def and defonce in this context?

reefersleep16:09:55

if you’re not using defonce, you probably should 😄

mrchance16:09:53

I've used reagent in several projects already, so I have a pretty good idea about the overall setup, but I've never seen this problem before

reefersleep16:09:21

ah well… I feel like I’m always hitting corner cases, even though I’ve done several (toy) reagent projects now, as well

reefersleep16:09:28

that is to say, I feel your pain 🙂

reefersleep16:09:11

(and one serious project, btw. It’s not all fun and games!)

mrchance16:09:14

I am really happy with it overall, but yeah, I've hit a few snags as well

reefersleep16:09:22

oh yeah, for sure

reefersleep16:09:35

I think it’s probably preferable to a lot of other approaches

mrchance16:09:45

as someone so eloquently said: "Out of all programming languages, Clojure sucks the least"

mrchance16:09:51

Same is probably true for reagent 😉

mrchance16:09:57

Nothing's perfect

reefersleep16:09:23

what that guy said ☝️

reefersleep16:09:26

curious to hear what you discover about the error

reefersleep16:09:59

if you can reduce the code so much as to become “anonymous”, with the error still persisting, and copy it to a project that does not include business names or other info, I could check it out and try to run it

reefersleep16:09:02

I use cider, too

mrchance16:09:31

I'll let you know: Preliminary result: renaming the var and also all parameter names didn't help 😞 Also, running the same just via lein figwheel produces the same error, so that's nice at least 😉

reefersleep16:09:43

yeah, that’s good 🙂

mrchance16:09:48

That's the most minimal example I could produce

mrchance16:09:16

Main difference from the template is that I made all helper functions take a parameter instead of referring to the global atom

mrchance16:09:08

I like my global state to be confined to a narrow space in the dev setup if possible

reefersleep16:09:04

and you tried with (defonce global-app-state (make-initial-state)), too?

mrchance16:09:34

Same result 😕

mrchance16:09:54

It's actually what I started with and then changed out of desperation 😉

mrchance16:09:16

The error appears in current-page

reefersleep16:09:09

when dereffing, on line 36?

reefersleep16:09:30

(defn current-page [state-ratom]
  (let [page-key (:page @state-ratom)]
    [(page page-key) state-ratom]))
the second line here, I mean

reefersleep16:09:05

or is it further down, in the component that you’re putting into the vector?

reefersleep16:09:55

I am not comfortable using defmulti and defmethod, btw, so I cannot tell whether you are using them correctly

gadfly36116:09:35

@mrchance at first glance, the ns declaration just says state instead of tools.state. Id try changing it (as well as using defonce ... definitely shouldnt be def) and then running (reload-config) in your figwheel repl

mrchance16:09:37

ah, no, that's actually correct, I removed the name of the app

mrchance16:09:42

(Incorrectly)

mrchance16:09:16

I fixed it in the snippet

reefersleep16:09:39

I’ll try to follow the flow in my REPL

mrchance16:09:07

I also changed the multimethod to this:

mrchance16:09:33

Same result

mrchance16:09:25

And the error occurs directly in the deref in current page @reefersleep , not further down. A println there also shows that it doesn't receive an atom

mrchance16:09:09

@gadfly361 Thanks for the template btw., it's really helpful. Have used it in several projects without problems before

reefersleep16:09:22

try to trace back and see where the value does come from. I guess, directly from the app state ns. so maybe that doesn’t help you

mrchance16:09:45

yeah, not really, it's all rather confusing

reefersleep16:09:52

racking my brain trying to come up with a way to detect the change

reefersleep16:09:34

not coming up with anything new… still think you should try to reduce the number of references to your state atom until the error stops occurring. And if it does not stop occurring, well, then I guess it’s a tooling problem

mrchance16:09:27

yes, might be the most sensible route. I'll let you know if I find anything. Thanks for looking into it

reefersleep16:09:41

and then you’ll probably want to look at your project.clj setup, and maybe your .lein/profiles.clj file

reefersleep16:09:56

and possibly your cider setup 😄

gadfly36116:09:55

@mrchance Ahh i have run in to this problem before

gadfly36116:09:08

it is because you abstracted out the argument to reload

gadfly36116:09:40

it will work if reload doesn't take an argument

gadfly36116:09:59

basically, on reload, it isn't getting it, which is why your deref doesnt work ... it is nil

mrchance16:09:51

But it shouldn't even be called on reload, or am I missing something?

mrchance16:09:10

The main function just gets called when the page is reloaded, right?

gadfly36116:09:31

nope, reload is called on reload, main is not

mrchance16:09:53

Ah, I see, that's in the project.clj

mrchance16:09:09

Funny that it's actually not nil, but some figwheel information 😄

mrchance16:09:15

That explains where that is coming from

gadfly36116:09:33

ah, well in any event, it isn't your global-app-state

reefersleep16:09:40

I thought of this, but thought I was wrong!

reefersleep16:09:04

That reload was parametrized… and thought to ask you just not to have that param

mrchance16:09:25

hm, could I just remove it from the project.clj? It shouldn't be necessary to reload it every time, right?

gadfly36116:09:47

figwheel works because of that reload

mrchance16:09:59

Also, it feels slightly wrong to have figwheel pass it additional parameters that just magically disappear because of the way js works 🙂

gadfly36116:09:59

if you remove it, your changes on save wont get pushed

reefersleep16:09:14

just omit your param?

mrchance16:09:26

Yes, that would probably fix it already

mrchance16:09:32

What's the difference to just :figwheel true ? I am reasonably sure I had apps that didn't call any reload functions

reefersleep16:09:37

btw @gadfly361 , did you have a good meetup in Copenhagen? Sorry I couldn’t attend

gadfly36116:09:16

@reefersleep Yeah, it was great! Some very nice people there 🙂 Got to meet your buddy @grav and a few others

gadfly36116:09:47

@mrchance I was trying not to reload the routes or the dev-setup

reefersleep16:09:49

neat! haven’t seen him in a while actually, he’s in Canada currently, I think…

mrchance16:09:16

Sure, my point is... I don't think you actually have to reload anything

mrchance16:09:42

The component is already mounted, and reagent will take care of refreshing it

reefersleep16:09:05

What you said.

reefersleep16:09:20

There’s nothing figwheel-specific about your reload function

reefersleep16:09:59

It’s just your mounting function 🙂

reefersleep16:09:44

and figwheel takes care of (in some other fashion) replacing your def’ed functions with their new versions

reefersleep16:09:55

maybe this is my cue to read up on how figwheel works

mrchance16:09:52

exactly, I just checked, in my projects before the reagent-figwheel template I never used the on-jsload hook.

mrchance16:09:22

I think it's just if you have to clean up other state, like say core.async channels or something

gadfly36116:09:26

can you try replacing with true using figwheel-template, because when i do, i don't get the updates as expected

mrchance16:09:13

Anyway, removing the parameter fixed it 🎉

mrchance16:09:27

:figwheel true also works, reloads like it should

mrchance17:09:37

Thanks for your help party-corgi

gadfly36117:09:55

I am assuming you did, but just to make sure since i am trying the same thing and getting a different result - you killed your figwheel repl and restarted it? not just running (reload-config)?

reefersleep17:09:02

np 🙂 will we get to see your app sometime?

mrchance17:09:16

yes, completely restarted it

reefersleep17:09:31

oh yeah, @gadfly361 is on to something, I always make sure to completely reboot stuff when I’m troubleshooting

reefersleep17:09:48

to avoid pesky state obscurances

mrchance17:09:07

Hm, unlikely, unless you happen to work for the particular large european company I am building it for 😉

reefersleep17:09:11

and you’re already onto that. great!

reefersleep17:09:21

I might at some point 😛

reefersleep17:09:35

currently, I work for the state of Denmark

mrchance17:09:48

yes, that's one of my core learnings with cljsbuild and figwheel as well, when in doubt, restart everything 🙂

mrchance17:09:16

Can you use Clojure for your work there?

mrchance17:09:16

It took some convincing to get my company to try it 😉

mrchance17:09:36

They already did a Clojure project some time ago, and apparently ran into some problems 😞

gadfly36117:09:59

If I follow these steps:

lein new reagent-figwheel foobar +routes
cd foobar
;; change :figwheel {:on-jsload "foobar.core/reload"} -->      :figwheel true
lein figwheel dev
;; change text in home page

gadfly36117:09:11

I don't see the updates

mrchance17:09:16

hrm, that's really weird, just stopped everything, did a lein clean and lein figwheel to restart it, and it still works

mrchance17:09:23

Let me see what I get with a completely fresh setup

gadfly36117:09:59

thanks! will be helpful for me to understand the diff between fresh template and your working version (assuming yours no longer has a defmulti)

mrchance17:09:33

yes, I removed it now

reefersleep17:09:42

@mrchance we use Clojure and Clojurescript (and reagent)

mrchance17:09:43

Aaah, I think I know why 😄

reefersleep17:09:54

it’s why I took the job 😄

mrchance17:09:12

Denmark sounds like an awesome country 😄

mrchance17:09:29

Hm, or do I... :thinking_face:

mrchance17:09:03

It might be because the homepage doesn't deref any ratoms..? Checking...

reefersleep17:09:40

it’s very atypical for Denmark, mind you! 😄

reefersleep17:09:00

it’s mostly Java and C# in the state-owned IT solutions, I’d venture

reefersleep17:09:08

this project is a very different beast indeed

reefersleep17:09:30

but Denmark is great regardless 😛

mrchance17:09:41

In germany it's probably mostly Visual Basic troll

mrchance17:09:18

@gadfly361 Ok, interesting, the reloads don't work for me as well, and deref'ing the atom doesn't change anything as well

mrchance17:09:26

Might really be an issue with the multimethod

gadfly36117:09:08

I tried changing the multimethod to a case statement (like i use in re-frame-template) .. but that didnt work either. what are you using for that?

reefersleep17:09:14

(he said, with great prejudice)

reefersleep17:09:29

about Visual Basic, I mean

mrchance17:09:45

Yeah 🙈 🤐

reefersleep17:09:46

gotta go, will check up on this discussion later

mrchance17:09:55

Thanks again, bye 👋

gadfly36117:09:02

Hmm, no luck with that either, thank you tho!

mrchance17:09:24

Weird, not sure what else is substantially different...

gadfly36117:09:58

@mrchance are you doing something like this by chance?

(defn ^:export main []
  (dev-setup)
  (app-routes)
  (reload))

(main) ;; <-- adding this

gadfly36117:09:07

That is the only thing i can think of

gadfly36117:09:31

because then figwheel would call that everytime on save and the reloading would work as expected

mrchance17:09:09

no, nothing of the sort

mrchance17:09:47

The only thing that's different apart from that is that I parameterized the app-routes function, but I don't see how that would cause re-renders

gadfly36117:09:58

I tried that as well with no luck. Thanks again tho!

reefersleep19:09:48

@mrchance @gadfly361 I'm having trouble figuring out what problem you guys are pursuing?

mrchance19:09:08

@reefersleep we're trying to figure out why figwheel reloads my code with just :figwheel true while it requires an explicit reload in the template

reefersleep19:09:09

I'll give it a go when I get the chance as well

reefersleep20:09:53

btw @mrchance , I got an arity error when I did

user> (defmulti page identity)
#'user/page
user> (defmethod page :home [] "sweetness")
#multifn[page 0x48e10697]
user> (page :home)
ArityException Wrong number of args (1) passed to: user/eval44477/fn--44478  clojure.lang.AFn.throwArity (AFn.java:429)

reefersleep20:09:57

but not when I did

reefersleep20:09:36

user> (defmethod page :home [_] “sweetness”)
#multifn[page 0x48e10697]
user> (page :home)
“sweetness”

reefersleep20:09:40

I haven’t seen a use case for defmulti/defmethod yet that was nicer than map lookup

mrchance20:09:47

interesting, yes, now that you mention it empty params should be incorrect

mrchance20:09:07

Java is more finicky in this regard than Js

mrchance20:09:24

The use case is multiple dispatch 😉

reefersleep20:09:53

oh yeah, you’re right!

reefersleep20:09:03

I thought I was in my cljs repl, but I was actually in the clj one

reefersleep20:09:28

I still get tripped up by cider/figwheel starting two repls, even after working with it for a year

mrchance20:09:39

Also, when there is some structure, since it supports hierarchy

mrchance20:09:48

Yeah, me too -.-

reefersleep20:09:59

maybe I just don’t grok multiple dispatch yet 🙂

mrchance20:09:27

I didn't use the cljs repl for a long time, since figwheel is so awesome and the piggiebacking setup was so tedious

mrchance20:09:45

Just got back to it thanks to the reagent-figwheel template 😉

mrchance20:09:29

But still, good find, I think the template should be changed to the correct arity defmethods

mrchance20:09:12

And regarding multiple dispatch: Another big advantage that I forgot is that multimethods are open, not so easy to implement with a map lookup

mrchance20:09:40

So it's nice for libraries

reefersleep20:09:01

I get that, but aren’t you doing an app where you own the lookup yourself?

reefersleep20:09:39

I’m down with the whole expression problem solution thingey, though I haven’t directly benefitted from it myself

mrchance20:09:22

Yes, I do, it's from the template, not my first choice 😉

dimovich20:09:34

hello, I'm getting this error WARNING: JSC_JS_MODULE_LOAD_WARNING. Failed to load module "react" at <...>/experiments/node_modules/create-react-class/index.js line 13 : 4

mrchance20:09:47

@dimovich When doing what, precisely? I think this needs a little more context 🙂

dimovich20:09:46

installing the modules with npm install

dimovich20:09:16

using reagent "0.8.0-alpha1"

mrchance20:09:54

woah, I didn't even know that's possible (strings in require form). I don't think it's correct though, you should check https://clojurescript.org/reference/dependencies#external-javascript-libraries for how to include foreign libs

mrchance20:09:25

Basically, check if there is a cljsjs library for what you want, and if not, provide some extra info in project.clj

mrchance20:09:39

And require it like you would a clojurescript library

dimovich20:09:52

the string form of require will lookup a node module

dimovich20:09:37

added cljs-react and cljs-react-dom to project dependencies

dimovich20:09:46

anyway, same error

mrchance20:09:27

What's your source for the string form? I don't think it's supposed to work that way

mrchance20:09:43

Also, I meant using react-draggable and resizable from cljsjs

mrchance20:09:29

e.g. [cljsjs/react-drag "0.2.7-0"]

dimovich20:09:34

re-resizable is not on cljsjs

mrchance20:09:44

Then I think you need to follow https://clojurescript.org/reference/dependencies#bundling-javascript-code, with a :foreign-libs key pointing to your node_modules

dimovich20:09:58

I'm doing that for the moment, with webpack -> :foreign-lib

dimovich20:09:12

but wanted to to try using directly the npm module

mrchance20:09:34

Why do you need webpack? Oo

dimovich20:09:16

thanks for the links

mrchance20:09:52

You're welcome 🙂

mrchance20:09:27

Sorry, don't have enough experience to help you there

dimovich20:09:07

nice the page multimethod idea... you could do [page @(subscribe [:current-page])

reefersleep20:09:37

but you can do that with page being a regular function, too

reefersleep20:09:11

I am apparently really against multimethods 😄

mrchance20:09:12

multimethods are awesome when needed, but that's really rarely the case 🙂

reefersleep20:09:31

@mrchance it seems that like @gadfly361 , I cannot get figwheel to reload on file changes properly with

:cljsbuild
  {:builds
   [{:id           “dev”
     :source-paths [“src/cljs”]
     :figwheel     true 

reefersleep20:09:24

maybe you have some project.clj cache lying around somewhere? Or maybe you have magic fingers. Who knows 🙂

reefersleep21:09:07

and btw, my CIDER setup did not work with that template. I needed to do lein figwheel in the terminal.

mrchance21:09:33

Interesting, I had that problem too, but only because I had underscores in my project name picard-facepalm

mrchance21:09:58

And it doesn't reload for me in the standard setup as well, but it does with the project I needed your help with

mrchance21:09:02

For whatever magical reason

reefersleep21:09:28

I have no underscores, so dno

mrchance21:09:48

¯\(ツ)

reefersleep21:09:54

love that emoticon

mrchance21:09:39

I know, right?

mrchance21:09:07

It's a pretty awesome emoticon

reefersleep21:09:20

that’s a first for me, that initialism

dimovich21:09:44

some multimethods 🙂

reefersleep21:09:45

Here’s my map version, @dimovich :

(def state (r/atom :page-1))

(defn page [lookup-key]
  (let [pages {:page-1 [:div “page 1”
                        [:button {:on-click #(reset! state :page-2)} “open”]]
               :page-2 [:div “page 2”
                        [:button {:on-click #(reset! state :page-1)} “close”]]}]
    (get pages lookup-key)))

(defn index []
  [page @state])

mrchance21:09:10

Here is my equivalent version for your version @reefersleep 😉

(def page 
  {:page-1 [:div "page 1"
            [:button {:on-click #(reset! state :page-2)} "open"]]
   :page-2 [:div "page 2"
            [:button {:on-click #(reset! state :page-1)} "close"]]})

reefersleep21:09:31

I don’t assume keyword-as-ifn-functionality in these chat sessions

reefersleep21:09:12

or map-as-ifn

mrchance21:09:11

One of my favourite things about clojure though 🙂

reefersleep21:09:34

though I use it all the time 🙂 it’s just that it can be a source of errors and confusion

mrchance21:09:05

yes, especially when you don't know how new someone is to Clojure

reefersleep21:09:54

yeah… or you’re binding “stuff” to symbols and assuming (wrongly) that “stuff” is always something that implements ifn for lookup

reefersleep21:09:06

not that this happens often, in my experience

reefersleep21:09:29

but I only really use keyword-as-ifn when I’m referring to the keyword literal in code

mrchance21:09:43

yeah, usually better

reefersleep21:09:53

that “Clojure is the least sucky language” quote really fit this entire chat session of ours - we’ve come upon and discussed a lot of ambiguousness and caveats in Clojure, Clojurescript, figwheel, leiningen, cider and reagent!