This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-02-22
Channels
- # architecture (9)
- # beginners (90)
- # cider (98)
- # cljs-dev (23)
- # cljsrn (4)
- # clojure (101)
- # clojure-brasil (3)
- # clojure-dev (48)
- # clojure-italy (15)
- # clojure-losangeles (3)
- # clojure-russia (12)
- # clojure-uk (17)
- # clojured (1)
- # clojurescript (141)
- # community-development (15)
- # core-async (1)
- # datascript (12)
- # datomic (18)
- # docker (3)
- # emacs (1)
- # events (1)
- # figwheel (1)
- # fulcro (57)
- # graphql (4)
- # javascript (9)
- # jobs (1)
- # lein-figwheel (1)
- # leiningen (1)
- # lumo (1)
- # off-topic (68)
- # om (9)
- # om-next (3)
- # onyx (4)
- # parinfer (6)
- # pedestal (14)
- # portkey (2)
- # proton (1)
- # protorepl (19)
- # re-frame (57)
- # reagent (46)
- # ring-swagger (12)
- # shadow-cljs (167)
- # slack-help (5)
- # specter (18)
- # sql (1)
- # uncomplicate (3)
- # unrepl (1)
Are there any general recommendations for clojurescript that might unavoidably have to deal with interop with a lot of stateful/mutable objects? I just started building a new reagent project that is coupled to the web audio API, essentially building a synth in JavaScript. But it already seems like a bad fit, unless there are patterns for dealing with this?
@hello721 my offhand thinking is that client-side webpages are inherently dealing with a stateful dom, so in a sense that’s a pattern
@lee.justin.m thanks for your thoughts! My pain at this point is dealing with reagent atoms. I'm keeping my stateful stuff in one, but because the objects I'm storing in there don't change, but their data does, things don't get updated/rendered properly. Perhaps that's a bad fit, and I'd be better off with plain ol' clojurescript?
so you’re storing javascript objects in reagent and then something on the javascript side goes and mutates the javascript object?
yea reagent won’t know about changes to the atom unless you use swap!
or reset!
. so you just need to make sure whatever callback does the mutation does it the right way
Ah thanks! I think I got confused because the state changed, so I assumed it was working!
reagent provides its own implementations of those functions (which is why you have to use a reagent/atom and not a normal clojure atom). they (and deref
) do all the dirty work of setting watchers and updating components
Ah thanks for kindly answering my n00b question! I guess I'm fortunate in that I've managed to avoid dealing with state in Clojure up to now 🙂 🙇
seems I am still having macro issues, if I am passed a list of symbols as a input to my macro, how do I resolve them to the same namespace as the macro is defined in, not the one it is called in?
Is there a list of macro variable resolution examples?
@shib.duman sure. there’s also #reagent if it is really reagent specific (I’m in there too)
@lee.justin.m thanks for that, didn't see the channel for some reason
if i may ask, i'm using bulma with reagent as my css and i'm just trying to create a tab set that actually activates the "active" state when clicking on the men or women tab shown here:
for whatever reason, the class isn't being updated on clicking on men or women, confused about why
is there a reason i'd need a wrapper function? this is essentially returning a reagent element that's mostly just hiccup stuff. i would assume that whatever comes out of the (let) section would just be acceptable.
in any case, i've added a wrapper function and now it's complaining about: TypeError: Cannot read property 'call' of undefined
it should look like
(defn men-women-tabs
[group]
(let [men-active-tab (atom "is-active")
women-active-tab (atom "")]
(fn [group]
[:ul {:class "tabs"}
[:li {:class (str @men-active-tab)
:on-click #(do (reset! men-active-tab "is-active") (reset! women-active-tab ""))}
[:a "Men"]]
[:li {:class (str @women-active-tab)
:on-click #(do (reset! men-active-tab "") (reset! women-active-tab "is-active"))}
[:a "Women"]]])))
you definitely need the wrapper. if you don’t write the wrapper, reagent will turn your original function into the render function of the react component, so every time the atom is updated, the original function is called. that original function promptly rebinds the atom
with the wrapper, the inner function gets turned into the render function, so the atoms don’t get rebound whenever they change
i’m not sure what your error is, however. this is the standard form for when you need local state. see https://github.com/reagent-project/reagent/blob/master/docs/CreatingReagentComponents.md#form-2--a-function-returning-a-function
so after fighting parinfer in atom i've got all the errors removed, but now instead of displaying markup like i wanted it to the function isn't displaying anything
i think however this is more an issue with my understanding of how reagent works as typically i've just been creating functions that return the appropriate hiccup trees (with methods attached if needed) in order to compose the dom
in any case, i really appreciate the help @lee.justin.m
one thing: put your custom components in square brackets. you’ll get yourself into all kind of confusing situations if you don’t
i must be in the 10% as i just wrapped a map call in that when it was calling the men-women tabs function and now it's throwing an error again
so if you want to call map, then you’ll call map with parenthesis, but when you use a component, you use [] so that reagent can call the component at the appropriate time
so like [:div (map (fn [something] [my-component something]) data)]
<-- see how we actually invoke map but return a vector from inside
great. I think the lesson of form-2 components and () vs. [] are probably the most subtle things about reagent.
the link i just sent you is a good explanation of the 3 different types of components. this is a way of understanding the () / [] thing https://github.com/reagent-project/reagent/blob/master/docs/UsingSquareBracketsInsteadOfParens.md
i’m trying to write a user manual but it hasn’t been incorporated into the project yet. this is way i think about it https://gist.github.com/jmlsf/17c588deb326e538dcea6847bc66db9b#how-reagent-renders
are you building for Node.js?
cljs.user=> (defmulti test-multi count)
#'cljs.user/test-multi
cljs.user=> (def ^:export test-multi-exported test-multi)
nil
(find a better name, though)
a common idiom is to use an asterisk for internal things/implementation details, like test-multi*
Just out of curiosity why the increased interest in lumo? I know what it is but I haven’t figured out why it is better to have a self hosted environment
I use it because it's a fast cljs repl for messing around and trying code
If I have a cljs lib A has npm-deps {B "0.0.1"}, is it possible to make project C that depends on A, also depends on B without declare in project.clj.
yes, you have to have deps.cljs
on classpath
@U05224H0W btw, does this work in shadow-cljs?
I’m writing a longish reagent component (i.e. a function) that is “object oriented” in the sense that I want local shared state between a bunch of related “methods”. right now i’m just writing them in a big let statement. it works, but i was wondering if is there a more idiomatic way to do this
if i understand you correctly @lee.justin.m re-frame subscriptions will give you that, or you could split out components which do the actual rendering and pass them the state they needs as props (from your let)
yea okay passing state is the other option but i didn’t want to go there. just want to make sure i’m not missing something
@lee.justin.m watch out for local states in let, if you rerender those component, the local state will also reset. I'd limit local state to something like input form text value etc.
well if you are doing something like manipulating a canvas, you need local state and you also want it to be reset when the component is freshly mounted
I'm reading strings using cljs.reader/read-string
for reading tag literals. However, plain strings are handles somewhat unexpected:
(cljs.reader/read-string "hey you")
hey
why is it that read-string
doesn't return the full string?it doesn’t even return a string - it reads the first full readable item in the string
@kurt-o-sys a popular hack is (read-string (str "[" s "]"))
which returns a vector of every readable item in the string
oh... right. So, I could try that hack, or add a tag literal #str
or so?
if you have a string, and want a string - why do any reading? just use the string
maybe I’m missing something
lol, yeah.
the point is, I'm parsing a bunch of serialized data
some of them are plain strings, some of them are tagged.
might I suggest a better serializing system? transit is great
yeah, will check. I thought using read-string would be more straight forward when it comes to reading plain strings 🙂
if I do (cljs.pprint/pprint foo)
it simply pretty-prints it as regular console.log info output. I want it the way so cljs-dev-tools make it expandable/collapsible kind of thing.
@ag js/console.log
directly
anyway, thanks @joelsanchez
js/console.log
-ing a clj data structure directly without cljs-devtools will result in an object full of cljs internal properties
that's why it's not done normally, only in the context of cljs-devtools
so I'm using persistent data.avl maps but I need to transit them over to the server. transit does not natively know how to serialize them. is there a better way to deal with this than manually invoke transient on them before serializing?
ah here: http://blog.cognitect.com/blog/2015/9/10/extending-transit. the official docs seem very light on this
@ag pprint
outputs a string. If, instead, you use js/console.log
you will output the actual cljs data structure and that's when clj-devtools kicks into action. A string will remain a string.
I'm trying to add tags, like e.g. #location. It works when I do it like this:
(cljs.reader/read-string
{:readers {'location tag-location}}
string)
however, I can't seem to register/add the tag so I can use it in my code like this: (def a #location {...})
I have tried:
(cljs.reader/register-tag-parser! 'location tag-location)
(cljs.reader/add-data-readers {'location tag-location})
(cljs.reader/register-default-tag-parser! 'location tag-location)
yeah, extending readers at runtime is a pain - this is part of what makes transit good
all give No reader function for tag
yeah. I understand that, but for now and I will have to check transit more in detail. can the readers be extended at compile time? (it doesn't matter to me in which phase they are extended, I just wonder how to add new tag readers that can be used run-time)
with transit? they are taken as an argument to the read function
not with transit, but well, I guess transit will be the one that I have to use. Reading is not really the issue anyway. I just wanted to use things like #location {...}
in my code. But #location
is not recognized.
argh transit handlers in clojurescript - why do I get: (cognitect.transit/write (cognitect.transit/writer :json {:handlers {clojure.data.avl.AVLMap avl-map-write-handler}}) (clojure.data.avl/sorted-map :id "huh")) #object[TypeError TypeError: self__.tag_fn.call is not a function]
same works in clj: (let [out (java.io.ByteArrayOutputStream. 4000)] (cognitect.transit/write (cognitect.transit/writer out :json {:handlers {clojure.data.avl.AVLMap avl-map-write-handler}}) (avl/sorted-map :id "hello")) (.toString out))
(def avl-map-write-handler (t/write-handler "avl-map" (fn [o] (into (sorted-map) o))))
the error message is actually fairly clear but the blog post happily passes a string, however cljs implementation requires the tag to be a function instead. so this works: (def avl-map-write-handler (t/write-handler (constantly "avl-map") (fn [o] (into (sorted-map) o))))
Probably obvious and dumb question, but I'm guessing the primary users of cljs are clojure users correct? I don't see the benefit of cljs if you don't have a clojure backend now that there is es6+.
I'm a clojure/datomic developer I'm doing a re-frame app with a golang backend. clojurescript does not target ES6. It target's google closure compiler.
yeah, I know that, what I mean is that ES6+ improved things a lot for JS. So JS today is pretty decent.
Yes but cljs is better AND has awesome , built in immutable data structures AND repl = much better than es6 IMO
cljs effectively has full proxies, which is years away from landing in js if ever. that enables super convenient state management. the expressiveness of specter does all of that spread operator nonsense really easily. immutable data structures makes all of those redux optimizations happen for free
@lee.justin.m what are full proxies?
what i mean is that there is a level of indirection in clojurescript datastructures which enables things like reagent’s atom technique to work perfectly. it’s pretty flakey in javascript because of the way arrays work (see the mobx library for an example of a library that tries to do this).
@lee.justin.m you use cljs in the node backend too?
partly that’s because of the other libraries and tools i’m using. it’d be nice to do it in clojure but my backend isn’t super complicated and node works and is fast and i don’t want to learn another effing way to deal with sql
i’m using sequelize, a bunch of pdf parsing crap, and, unfortunately, sequelize/postgres (and also elasticsearch). cost/benefit is not there. also, i hate java and its entire ecosystem with the passion of a thousand burning suns. 🙂
also node + cljs is even less mainstream than cljs is to begin with so i don’t even want to know what the tooling is like
but i don’t regret for one second leaving behind all that redux boilerplate (and all of the flowtype I had to use to make it manageable)
no. those frameworks are way over-engineered for my needs. maybe it makes sense if you have 10 people working on a project. not sure. probably helpful to use one as a learning project because it can help you structure your code. but i find it much easier to do things without the crazy complexity of re-frame. I keep all my state in a big map and have mutators that wrap specter and always run synchronously. then i have an “rpc” module that does asynchronous stuff with server calls and updates state once its done. this basically replicates redux’s actions/reducers without boilerplate.
this kind of stuff is cray: https://github.com/Day8/re-frame/blob/master/docs/Coeffects.md
I did try rum. I liked it actually, but I could not figure out how to do interop with react libraries, and basically there’s one guy in an asian timezone who knows what the hell is going on with that library, so that wasn’t working for me.
but the differences with react are really ergonomic. they both provide roughly the same offering.
I am happy with Cljs on Node for AWS Lamda though prefer Clojure on jvm for a backend
@U0522TWDA That's interesting. Can you point to an example of the configuration you use for cljsnode on Lambda?
No, it isnt public. What do you mean by “configuration”? I use serverless-cljs and custom :cljsbuild config with :advanced (would love to try #shadow-cljs when I have time)