Fork me on GitHub
#clojurescript
<
2017-11-01
>
vinai06:11:41

I'm integrating with an existing app built with requirejs and knockoutjs. All is peachy until compiling with advanced optimizations. How can I specify the "types" of objects requirejs passes to my functions, e.g. in this bit of code:

(defn subscribe-login-state [subscription-fn]
    (.require js/window
            (array "some/module/customer-data")
            (fn [customer-data]
              (let [customer (.get customer-data "customer")]
                (.subscribe customer #(subscription-fn (boolean (.-fullname %)))))))
The require is easy to add to an externs file. Bit what about the get method on customer-data, or the subscribe method on the customer? The .-fullname property I can get around with using (aget % "fullname"), but I would not like to have to do that for all methods.

vinai06:11:29

Is it possible to type hint customer-data and customer, and then add those to an externs file?

maleghast09:11:30

Good Morning everyone… So, put simply, how do I “de-render” a Reagent component so that I can render another one..?

fbielejec10:11:26

Just like in vanilla react, you need to override shouldComponentUpdate lifecycle method: http://buildwithreact.com/article/optimizing-with-shouldcomponentupdate

maleghast11:11:53

OK, thanks 🙂

jbrown10:11:34

@maleghast i've had luck by providing a metadata key that deref's an atom for the component. When the atom (and therefore the key) changes reagent will de-render the component and render a new one associated with the new key.

jbrown10:11:18

Not sure if this is the best solution though. Would be interested to see if anyone has a better one.

maleghast10:11:36

Thanks @brown.joshua49 - I will investigate that as well…

jbrown10:11:11

Your welcome, i spent quite awhile the other day researching that 🙂. It seriously tripped me up that updating the react component is not the same as de-rendering and rendering a new one.

pesterhazy11:11:36

@maleghast what do you mean by "de-rendering"?

maleghast11:11:49

@pesterhazy - I mean the ClojureScript / Reagent equivalent of pulling some markup out of the DOM and inserting some new markup in its place.

maleghast11:11:45

i.e. “render” in React/Reagent land is “make markup, push into DOM”, so “de-render” would be “take markup out of the DOM”. Clearly I would “render” to put the new stuff in place - I can see that.

pesterhazy11:11:03

This seems like a basic React question. If you don't have React experience, a good React tutorial would be a good place to start.

pesterhazy11:11:20

In a nutshell, you don't take markup out of the DOM. Instead, you just don't emit the corresponding React elements the next time the component renders, and you do something to cause the component to rerender.

maleghast11:11:21

@pesterhazy - Yes, that has broadly been established ^^ and I have been looking into such things between conference calls. I was casting around, hoping that someone would say “oh that’s easy you just…” and I could crack on, but no matter, and thanks anyway 🙂

pesterhazy11:11:46

In React that would be changing this.state; in Reagent we use ratoms for that.

pesterhazy11:11:00

(def hidden? (r/atom true))

(defn my-comp []
   (if @hidden? [:div] [:div "Here I am. Look at me!"]))

pesterhazy11:11:11

would be a simple way to do it

maleghast11:11:28

That seems pretty elegant / simple - thanks for that 🙂

pesterhazy11:11:56

To cause the state change, you just need to (reset! hidden? false) in an event handler

pesterhazy11:11:09

Next step would be to use a global state atom for that.

Ben Redden11:11:49

total newb question. ive just been learning Clojure for a few weeks, im mainly a JS dev in my day to day. does anyone have a good video/article about getting started with Clojurescript and front end frameworks, like React/Angular ?

Empperi11:11:14

you really shouldn’t use react or angular directly with ClojureScript, that doesn’t make sense really. You should use a ClojureScript library (and most of those wrap react, so not all of your react knowledge is lost) built for that thing

Empperi11:11:29

I personally love reagent+re-frame combination but your milage may vary

Empperi12:11:58

it would be easier to first use just reagent and then add re-frame on top of that later. Although you’ll most likely end up rewriting your frontend that way but everything you learn while using just reagent still is very much valid when using re-frame

leonoel12:11:46

hi, is the &env hack still the official way to detect the target environment inside a macro ?

mfikes13:11:27

@leonoel It was never official, but it should still work AFAIK.

maleghast13:11:13

@pesterhazy - Just wanted to update you… The behaviour I was looking for is perfectly executed by rendering a new component in the same DOM location. Thanks!

pesterhazy14:11:06

@maleghast glad you got it to work!

grzm15:11:16

Hi! I've got a test that's failing under advanced compilation settings. Other tests are running fine. I'd like to exclude only this test when running under advanced compilation. I'm using lein cljsbuild. Any pointers as to how I might accomplish this?

grav15:11:56

@grzm A bit crude, but maybe you could put the test in a separate file, and then not include that file it in the build configuration that uses advanced compilation?

grzm15:11:58

@grav yeah, that's an idea I had as well. thanks for confirming it may be worth pursuing.

grav16:11:49

No problem. Still, it seems a bit like a hack to me, and may result in lots of duplication in project.clj

grav16:11:43

There’s some documentation regarding test support here, although I can’t seem to find anything that fits your problem well: https://github.com/emezeske/lein-cljsbuild/blob/1.1.7/doc/TESTING.md

grzm16:11:29

that's why I thought I'd ask trying it 🙂 Taking a step back, do you think my original question is a reasonable concern that may not have been addressed yet? I find that sometimes when I'm too close to the problem I'm missing the bigger picture.

grav16:11:24

Yup, know that feeling. My only experience with :advanced is that it poses some challenges, and that it’s not always relevant. So I have to admit I only use :whitespace.

dnolen16:11:04

@grzm I would figure out why that test is failing first

dnolen16:11:21

this can be usually be done with :pseudo-names true, :pretty-print true

dnolen16:11:28

other than that, use :main

grav16:11:38

In any case, it’s interesting to have the failing test as documentation for when you’re ready to investigate further.

grzm16:11:55

@dnolen I'm trying to get the file and line number from a stacktrace: I'm hacking on the tooling in test.check

grzm16:11:45

From what I've seen so far, under advanced compilation I'm not able to get back to the original source file

dnolen16:11:05

since I don’t have any details I can’t tell you anything more

dnolen16:11:21

but that’s not generally true - source mapping works through advanced compilation

dnolen16:11:49

if you’re using the testing documentation helper macros that could also help

dnolen16:11:56

cljs.test/testing etc.

grzm16:11:55

The code that's handling the check is here:

grzm16:11:55

I'm more familiar working in the clj space than the cljs space.

grzm16:11:20

+ the required assertions.* files. The clj stuff works fine, as does nodejs with :none

grzm16:11:51

Though the short answer appears that I should be able to get it working. So, back into the code.

pawel.kapala16:11:32

How would you write this: 1. (JSON/stringify #js {:foo "a-foo" :bar "a-bar"}), or 2. (.stringify js/JSON #js {:foo "a-foo" :bar "a-bar"}) The latter does not yeild a warning, so it might be the correct one, but I’m trying to understand how does 1. even work? Or is there better way to convert arbitrary structure to json, that I’m missing? Thank you.

noisesmith16:11:27

the first one errors because JSON needs to be namespaced via js/ unless you created it as a new binding yourself

noisesmith16:11:56

in my cljs repl it doesn't work - I can't tell you why it works in yours

p-himik16:11:38

Interestingly, JSON/stringify works here http://clojurescript.net/ but not here http://clojurescript.io/

pawel.kapala16:11:53

I’m using figwheel in react-native, maybe that’s a factor here? In any case you suggest I go with version 2.?

noisesmith16:11:29

that's the one that actually matches the cljs docs yes

thheller16:11:56

@pawel.kapala (js/JSON.stringify #js {:foo "a-foo" :bar "a-bar"})

noisesmith16:11:09

that's also acceptable yes

hmaurer17:11:39

Hello! Quick beginner question: is there a nice devtool for any of Om Next / Reagent / Rum / else? Om Next has some notion of state management, the others do not, but I am wondering if there is a nice setup with any of these to get state management (ala redux) with a tool to do time-travel debugging, etc

zalky17:11:02

@hmaurer: for reagent/re-frame, I've very much liked: https://github.com/Day8/re-frame-trace Was pretty easy to set up. Also there are some great resources here (including stuff on time-travel): https://github.com/Day8/re-frame/blob/master/docs/External-Resources.md

hmaurer17:11:27

re-frame-trace seems neat!

zalky17:11:11

Yup, it provides a really great debugging/introspection story (but only if you're using re-frame, not reagent on its own).

mfikes20:11:21

@pawel.kapala I now prefer the form (.stringify js/JSON #js {:foo "a-foo" :bar "a-bar"})). It is definitely correct, and you will get a helpful compiler warning if JSON happens to be a local as in

cljs.user=> (let [JSON 1] (.stringify js/JSON #js {:foo "a-foo" :bar "a-bar"}))
WARNING: js/JSON is shadowed by a local at line 1 <cljs repl>

noisesmith20:11:21

the js/foo.bar syntax always feels uncanny valley to me - not quite clojure and not quite other-language, even though I know it works

pawel.kapala20:11:52

@mfikes thanks! Still I wonder how is it technically possible to execute 1. Is there JSON namespace out there? Planck produces correct result but with a warning it wouldn’t find JSON ns..

pawel.kapala20:11:00

cljs.user=> (JSON/stringify #js {:foo "a-foo" :bar "a-bar"})
             ^
WARNING: No such namespace: JSON, could not locate JSON.cljs, JSON.cljc, or Closure namespace "" at line 1 
WARNING: Use of undeclared Var JSON/stringify at line 1 
"{\"foo\":\"a-foo\",\"bar\":\"a-bar\"}"

mfikes20:11:35

It just happens to generate JavaScript that works. Try planck -v and you'll see this. But it is just an accident related to the way namespaces and contained Vars are implemented as nested JavaScript objects.

noisesmith20:11:57

oh wow - now that I double check, my repl was doing the same thing - it just printed the warnings after the correct output so I missed it

pawel.kapala20:11:00

@mfikes Now I see it, so 1. is definitely wrong way of writing it. It is just a coincidence it actually works.. Thank you for clarifying this!

wpcarro22:11:39

Any garden users in the house? I have a question about using the garden.color records inside of my defstyles code…

wpcarro22:11:19

I’m wondering if it’s possible to specify to format of the CSSColor record as either hsla hex without calling the as-hex or as-hsl functions directly… perhaps there’s also a way to implement the toString protocol on the type… I’m new to Clojure so I’m unsure, but I imagine that there is something that’s converting the record into a string before writing to the .css file. Any direction would be appreciated.

wpcarro22:11:23

Are there are serious performance implications I should be aware of before implementing a toString protocol on a record or a type? I’m looking for whichever protocol is used when (str ...) is called