This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-26
Channels
- # aws (4)
- # beginners (21)
- # boot (12)
- # cider (3)
- # cljs-dev (1)
- # cljsrn (10)
- # clojure (190)
- # clojure-nl (1)
- # clojure-russia (7)
- # clojure-spec (1)
- # clojure-sweden (9)
- # clojure-uk (30)
- # clojurebridge (1)
- # clojurescript (105)
- # cursive (4)
- # emacs (8)
- # jobs (1)
- # jobs-rus (4)
- # klipse (1)
- # luminus (5)
- # om (3)
- # onyx (2)
- # pedestal (5)
- # powderkeg (15)
- # re-frame (13)
- # reagent (1)
- # ring-swagger (5)
- # rum (5)
- # vim (8)
@ashnur do you have any examples of tools based on datascript that would be better than vue.js?
I am tasked with creating a google-maps like app but with medical imagery as the "map" ad I would love to do it in clojurescript
@mikepence no reason not to use React + Om.Next or Reframe for that
Any UI framework that is functionally pure is better to a mutable one, IMO
It looks like Vue is mutable?
appears that vue is declarative and handles the updating of references and whatnot internally
Could work, but React has more traction in CLJS at the moment
tbaldridge: hi Tim..Recently watched your short YouTube tut on Pedestal..When can we expect the next ones..I really liked what I saw;)
won't know til later in the week how much leeway I have to use something like clojurescript
So getting help for vue may be harder
There was a guy in the audience who just kept asking "So how do you do two-way binfing, like in Angular"
But my point was that if you carry important data on the controller on Angular you deserve what you get 😉.
That said, it's not a bad thing to enforce discipline at both the language and the framework level... which is why I'm here and not in #Angular
In Clojure the eval
function is available in clojure.core
. Any idea where to find it it ClojureScript?
Ok so according to the sources It looks like it lives in cljs.js
, but for some reason I don’t have that namespace available (`cljs.js` is nil
).
cljs.user=> (require '[cljs.js :as s])
#object[Error Error: goog.require could not find: cljs.js]
hmmmAfaik, only bootstrapped Cljs has an eval (since you need something that will compile the supplied expression to js). More info here: http://blog.fikesfarm.com/posts/2016-01-22-clojurescript-eval.html
David Nolen states something about eval requiring pulling a lot of extra stuff, and that it doesn’t work with advanced compilation. Don’t know if that could be related to the error you get. https://groups.google.com/d/msg/clojure/FafbgirNa3A/Pjp68tjfBAAJ
Thanks @U052XLL3A. It “magically" started working in the end, I’m not entirely sure why.
So if I didn’t explicitly write a require
for cljs.js
it would not be available in the REPL.
@mikepence personally I prefer Om.Next's model because it is explicit. With Reframe (and Reagent), your components can access whatever global state they want and act on it. In Om.Next components must declare to Om what data they want to use, and the library notifies the components when the data is available and hands them the data. The net result is a system with explicit (but not static) connections between components. This is very powerful, since Om.Next can be free to batch HTTP requests, de-de-dup requests, etc.
In addition, nothing is stopping someone from providing specs for those component inputs and outputs, enabling generative testing for the UI.
This is all next to impossible in Reframe, since reframe uses implicit dependencies. It might be possible to hack something like this into Reframe, but it comes by default in Om.Next
@tbaldridge do you think subscriptions in re-frame are all that different from queries in om.next? why?
I think the concepts are pretty similar, the difference being with subscriptions, you don't need to worry about 1) passing as many props, and 2) worrying about what the component path is, both of which are a source of errors
Implicit vs explicit
Also, what does Reframe give you if the path doesn't exist due to a async load?
In on, render doesn't get called until all the required data exits
Also reframe stores these subscriptions opaquely in closures, in Om.next they are public
If components in re-frame exposed said what their subscription as a separate thing (outside the render method), I'm not sure what it would enable. Batching of requests would already be possible by just wrapping whatever function is sending requests, no?
Well that depends on your subscription - you could make it say {:state :pending}, for example, and then show a loading indicator
Some people say you are not supposed to do these kind of things in subscriptions, but I've yet to hear a good argument for it
It enables testing, bulkbloading (via stuff like graphql), and introspection. In short there's more leverage. More ways to use the data provided to add new functionality without modification of the components.
With reframe the library is completely blind as to the needs of your component. With Om the library can introspect and optimize
Building on what @tbaldridge said, I feel it's important to clarify it's not all perfect in Om Next. For one, your queries must match the UI component tree, which is sometimes really hard to model. It also gives you too much power, meaning you have to do stuff by hand that sometimes you wish the framework did for you. Things like knowing if you have all data to render (compared to stuff like Relay which has readystate
and won't render if it doesn't have all data) is manual, introspection is really hard since there's no well-defined, typed schema like in GraphQL (which again you can probably implement by hand and with Spec, but who wants to implement a type checker in every app?), etc
That said, this is all stuff that Re-frame also doesn't provide, but I'd use a library on top of Om Next that took care of these for me
I was up all night looking at various things: reagent, re-frame, quiescent, om, and rum. Rum was cute, but om next really struck me as the kind of pure idiomatic clojure that I so love to write.
FWIW, I've found re-frame to be be quite good, and have a nice built in solution for most things. And no complicated, error prone concepts.
@tbaldridge >With Reframe (and Reagent), your components can access whatever global state they want and act on it. Using the same logic, Clojure is equally terrible too. After all, functions in Clojure can access whatever global state they want and act on it. But is that way you choose to do, Tim? No, it isn't. So equally, there is absolutely no reason for you to do it in re-frame. In fact, the ENTIRE design of re-frame discourages it. So why would you make this claim so authoritatively? It is just wrong.
Can you show me a reframe example that does what you describe? Code is easier to discuss.
PLease just read the docs
It doesn't seem you understand re-frame at all, if you are making these claims
I have read the docs.
What I'm saying is the entire structure of reframe is implicit.
You do stuff then ask the library to figure out how it relates to your rendering code
> With Reframe (and Reagent), your components can access whatever global state they want and act on it. As you can see, from the above, I am in the first instance specificially calling out this misinformation
Is that statement wrong?
Because if that is your measure, then you shouldn't even be using Clojure. Because it is equally true of Clojure functions.
Nothing about re-frame encourages the use ofglobals.
Not really, Clojure is statically compiled, if someone use resolve thought their entire Clojure app, then I'd complain about that as well.
Bleh on a phone
@mikethompson now that I'm back at my desk , let met give you and example from the Reframe examples: https://github.com/Day8/re-frame/blob/master/examples/todomvc/src/todomvc/views.cljs#L52-L53
That code is fully dynamic, and opaque to the Reframe library. the library (or framework since both Om.Next and reframe are more like frameworks), has no way of knowing if every call to render will require the same data, or if it was just this one time. There's no way to express when your subscriptions could change, or what drives these changes.
In essence it would be like writing Clojure code like this:
(@(resolve "clojure.core" "println")
((@(resolve "clojure.core" "vector") 1 2))
If we wrote code that way ^^ it would drastically reduce the amount of optimizations Clojure could perform on the code.
So with code, and with my UI, I prefer to hand as much information to the framework itself, so it can leverage that information for better tooling, performance, documentation, etc.
so you're saying, for instance, a type system could check at compile time with om whether a function has correct constraints in a given form, whereas with reframe it couldn't? Or something like that?
No, I'm saying it cuts back on introspection. As far as Reframe is concerned a render function is just an opaque bit of code. It runs the code then sees what the component subscribes to, to try and figure out what the component requires. so it has to run the render to get its dependencies. The same is true in Reagent.
I'd just prefer a model where the framework can query some component and say "what are the parameters you expect", "what is the data you expect?",
absolutely, Reframe is great for some tasks, I just tend to have a different set of priorities and needs
I resisted reframe for a long time for fear of some of the warts/practicalities but it's proven very effective for some large enterprise apps.
I would love some direct response to the om.next query building feature
@tbaldridge While I can certainly see that hierarchical GrophQL-like query composition is a nice win in some apps, for mine it is not important. Other considerations are much more influential. So, yes, priorities. As always. And that's why I didn't address that issue above. I was instead disagreeing with a different aspect of what you said - the part I highlighted - I didn't feel I could let that float past without a challenge. (Which has now been done, so we can probably move on)
Well, but since you're here, let me ask you this: aside from any politics of what framework is better than another, doesn't it seem better to have explicit, queryable (as in you can say 'find all components that require X'), introspect-able components?
And to your point though that reframe doesn't use global state, at least any more than Clojure, I don't know that I understand. Doesn't that example I linked show otherwise @mikethompson?
What is @(subscribe [:foo])
but accessing global state?
And yes I realize, saying "isn't X better" ignores the additional book-keeping that may require the programmer to maintain.
Monday morning here, and I need to kick start a busy week. So I don't have much time, I can only reiterate what I said before, I don't find I have much use for knowing all components which access X - particularly when in my world, there can be a layering of subscriptions (materialised views). But I'm sure that it is wonderful for a sufficiently hierarchical set of views, and a sufficently graph-like data store in the backend. Like I said, priorities.
And, yes, subscribe
is clearly a method for accessing what is ultimately global state.