Fork me on GitHub
#re-frame
<
2020-06-06
>
mikethompson03:06:24

@ray.stubbs @isak Within Clojure, the purpose of symbols is to provide bindings - names for values, often function values. Whereas, keywords provide identities. keywords evaluate to themselves, not something else (which, of course, symbols do). As a result, keywords are more data-like, which is exactly why they are in the language. And we want to use data as much as possible. This may help https://day8.github.io/re-frame/data-oriented-design/

3
3
mikethompson03:06:11

Fundamentally, we want the code which dispatches an event, or subscribes to a query, to have no clue about the eventual implementation (no coupling) . keywords are pure data, and data is declarative by nature, which is a good thing.

lilactown04:06:09

it makes it harder to do things like code splitting tho if you have keywords used ad-hoc everywhere without requiring the ns that implements the event or sub you're using

lilactown04:06:03

I think it's fine to have a use a symbol that refers to an identity which is used throughout the system as data

👍 4
lilactown04:06:12

preferable, even IMHO

mikethompson06:06:44

> it makes it harder to do things like code splitting tho if you have keywords used ad-hoc everywhere without requiring the ns that implements the event or sub you're using I've never had this problem, probably because we don't need to code split. So, I'll have to take your word that its a problem. Having said that, we aren't very "adhoc" about the keywords we use. Doing anything "adhoc" is ultimately a problem when you later need more structure.

mikethompson06:06:07

> I think it's fine to have a use a symbol that refers to an identity which is used throughout the system as data I can't parse this sentence. Perhaps because I don't consider symbols as an identity. They are a name which is bound to something. When you evaluate them, you get the thing they are bound to. If they are good identities, why does Clojure have keywords? As I understand it, because keywords evaluate to themselves, making them the perfect identities, a bit like how 4 evaluates to 4, except keywords are more descriptive. And, that, as I understand it, is why we have keywords in the language.

p-himik08:06:13

I think lilactown meant something like (def do-stuff-event-id :events/do-stuff) so that later you could require the ns that contains do-stuff-event-id.

mikethompson06:06:02

Anyways, the good news is that all opinions work because re-frame doesn't actually demand that you use keywords.

mikethompson06:06:57

You can even do this if you want:

(reg-event-db 
   [:a 'vector "if you want"]    ;; <-- not a keyword
   (fn [db e]
     ...))

👍 4
David Pham09:06:28

Does it work with sets as well? :) Making dispatch on sets or maps would be fun.

mikethompson06:06:35

Then:

(dispatch [[:a 'vector "if you want"]  <other>])

mikethompson06:06:15

Each to their own, but I, personally, won't be doing that

mikethompson06:06:50

And I won't be using symbols, because for me it creates an unnecessary, unwelcome coupling. But, hey, I've been wrong before.

🎉 8
Harshana08:06:26

Hi. I'm a beginner in re-frame. I tried to create a project using lein new re-frame . When I ran the application using lein dev , it gets rendered but "shadow-cljs connection closed" pops up as soon as the page gets loaded. None of the events work. I git cloned another re-frame project and ran it. It is working fine. I compared the project.clj files and there is no :cljsbuild key in my project. Is that the reason?

p-himik08:06:20

If you're using shadow-cljs, then you don't care what project.clj contains since shadow-cljs doesn't use that file. That file will be used if you use shadow-cljs via lein, but then :cljsbuild should not be present AFAIK because only shadow-cljs should build CLJS files.

Harshana08:06:39

Thanks. What should I do next? Even a button click doesn't work now. Shadow-cljs connection gets closed as soon as the page gets loaded.

thheller08:06:07

check the browser console. does it say anything why it was closed?

Harshana08:06:22

It says webscoket error

thheller08:06:07

does it say why?

thheller08:06:45

it should be connecting to localhost:9630 which would be the shadow-cljs main server. did you maybe block that in your firewall or so?

Harshana08:06:36

IG that's the problem. It says Can't establish connection to the server at localhost:9630

thheller08:06:36

what do you get when you open http://localhost:9630 in your browser?

thheller08:06:24

you are accessing this all locally I presume? or is running in some of container/virtual machine?

Harshana08:06:48

yes, I'm accessing it locally. When I open http://localhost:9630, it is blank.

thheller08:06:18

thats weird. it shouldn't be. any errors in the console there?

thheller08:06:06

what does it say on startup? it should be logging something like shadow-cljs - server version: <version> running at

Harshana08:06:07

Just this: The character encoding of the plain text document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the file needs to be declared in the transfer protocol or file needs to use a byte order mark as an encoding signature.

Harshana08:06:42

Now I get this error in the terminal: ERROR: UT005071: Undertow request failed HttpServerExchange{ GET /ws/worker/app/550c2156-ce6d-45e8-bf19-f1cd4390a1ee/ca23dabe-004a- 4ae5-bc5c-60944bd623c5/browser}

thheller08:06:44

and more to that error? any hint why it failed?

thheller08:06:08

which shadow-cljs version is this btw?

Harshana08:06:53

Caused by: java.lang.OutOfMemoryError: Java heap space from the UncaughtExceptionHandler in thread "dev-http-file-watch"

thheller08:06:29

what the heck

thheller08:06:48

which directory do you use as your :dev-http? does that have like a billion files in it?

thheller08:06:17

how much memory do you have available?

Harshana09:06:35

harddisk memory? around 400 gb

thheller09:06:32

hmm that should be enough. how much is actually free though? the file-watch really shouldn't consume that much memory.

thheller09:06:03

you can set :jvm-opts ["-Xmx512M"] to constrain the memory use of shadow-cljs down to 512mb which is usually enough

thheller09:06:31

but you didn't answer which version you are using?

thheller09:06:45

hmm that should be fine. some older versions consumed more memory than they should but that has long been fixed.

Harshana09:06:20

I cloned another git repo that uses figwheel. None of these errors came with that. It is working fine. Is figwheel an alternate to shadow-cljs?

thheller09:06:38

sure you can use figwheel too

Harshana09:06:33

Cool. How do I create a re-frame app with figwheel and not shadow-cljs? The documentation says the base template comes with shadow-cljs.

thheller09:06:01

I don't know.

Harshana09:06:44

Okay. Thanks 🙂

Harshana10:06:30

@U05224H0W After changing the max heap size, it's working fine now. Thanks!

👍 4
Mikko Koski11:06:46

@mikethompson So if I understand right what you're saying, you wouldn't recommend this:

;; a.cljs
(ns a)

(reg-event-db
  ::my-handler
  (fn [db] ...))

;; b.cljs
(ns b
  (:require [a]))

(dispatch [::a/my-handler ...])
...because this introduces a coupling between the two namespaces a and b, and the code in namespace b which dispatches the event should have no clue about the handler registered in namespace a. Did I understand right? I'd be really interested to hear more why the coupling and the need to require the namespace is considered unwelcome. This is the pattern I've used in the app I've been building and it has been working very nicely for me.

p-himik11:06:10

I've been using this pattern for about 3 years now. For me, it works better than manually assigning namespaces that don't correspond to any actual namespaces.

👍 12
folcon11:06:09

My read of his explanation is that that’s ok, but not required? I could be totally off base, but I’ve done that, and I’ve also done this:

(dispatch [:a/my-handler]) ;; <-- no double colon
I find it really useful that both of these patterns are supported…

p-himik11:06:35

::a/x - here ::a is replaced with the namespace that you requried, it's an alias. :a/x - here a is the namespace. It's not an alias.

folcon12:06:29

Yep, I’m aware, but :a/my-handler doesn’t need you to require the namespace in question, which is useful at times vs ::a/my-handler which does…

p-himik12:06:22

Yep, but you'll have to also call (reg-event-db :a/my-handler ...) instead of (reg-event-db ::my-handler ...). Different approaches, both work, each has pros and cons.

folcon13:06:55

Yep, hence that flexibility is a plus in my book =)…

David Pham19:06:20

I think you need discipline when you refer to events from other namespace. Something like private/public or local/global events or some notions of events might be shared to other namespaces. The reason is you might be less strict on change for local events. I usually have 3 contexts in my apps: components (where events/subs are fully qualified and defined in the same file, and events only concerns the views defined on that file, components are meant to be shared across all panels), global events/subs (non qualified keywords probably shared by all panels), panels events (fully qualified keys as well).

David Pham19:06:02

The trick starts when you have to share events between panels, and I defaulted to global events for exchanging information.

David Pham19:06:25

I served me well for the last year and half, but maybe I am missing something.