Fork me on GitHub
#clojurescript
<
2022-04-16
>
thheller05:04:02

master does but no release just yet. should be coming soon.

Simon10:04:59

Happy Easter Clojurians! I hope some of you out there are online and interested in helping me out 🙂 I have this component:

(defn component [id]
  (let [status (r/atom nil)
    (debounced-api-call! status id)
    (fn []
      [:h1 (str "the result is: " @status)])))
I want the API to be called every time the prop id changes. Right now it only gets called once, when the component is rendered.

p-himik10:04:03

Either create a form-3 component and make the check for a different id in :component-did-change or add a ratom, something like internal-id, reset! it to id in the outer fn and check whether it's equal to the new id in the inner fn. Alternatively, don't do it in the component at all - do all the data related stuff where the data resides.

Simon11:04:04

I’m attempting your second suggestion. Can you clarify how that would look in my example?

Simon11:04:53

This doesn’t work:

(defn component [id]
  (let [status (r/atom nil)
        internal-id (r/atom id)
    (fn []
      (when (not= @internal-id id) 
         (reset! internal-id id)
         (debounced-api-call! status id))
      [:h1 (str "the result is: " @status)])))

p-himik11:04:17

The internal fn must also accept [id].

p-himik11:04:29

Otherwise, the changes to id never make it to the view function - the value from the outer scope gets closed over.

Simon11:04:00

ah of course. Thanks!

pinkfrog14:04:04

Why for some objects, say the name is *a, when I type *a in the console, it only shows

#object[Error Error: Network Error]
If I test with (js-keys *a) , it shows the output:
#js ["config" "request" "response" "isAxiosError" "toJSON" "clojure$core$protocols$Datafiable$" "clojure$core$protocols$Datafiable$datafy$arity$1"]
However, for some other objects, typing them in the console, it will directly show in the
{"asdf":"asdf", "xxx":"yyy"}
format.

lilactown14:04:28

by console do you mean the REPL?

lilactown14:04:20

when you print an object, cljs looks at the prototype of the object to see if it knows how to print it. e.g. for maps and vectors, it would print it like EDN. if an object has the Object prototype object, then it will print it by enumerating its keys and values.

lilactown14:04:52

if it doesn't find a prototype that it knows how to print, it just calls .toString on it

lilactown14:04:16

it's easy to create an object that is an instance of Object, e.g.

#js {:a 42}
;; => #js {:a 42}

(doto (Object.)
  (goog.object/set "a" 42))
;; => #js {:a 42}

lilactown14:04:15

it sounds like your a* isn't an instance of Object, but something else. e.g. an axios request object created from a class

lilactown15:04:14

objects that are created from new SomeClass have SomeClass on their prototype, not object. so cljs doesn't know how to print them by default

pinkfrog15:04:27

That makes sense. But (js-keys) still has the ability to inspect the keys even if the object is of SomeClass.

lilactown15:04:36

yep that's right

pinkfrog15:04:52

(def e (js/Error. "test string"))
  (js-keys e)

pinkfrog15:04:24

For the above, (.-message e) gives the error message. but (js-keys e) gives weird things like

#js ["clojure$core$protocols$Datafiable$" "clojure$core$protocols$Datafiable$datafy$arity$1"]

lilactown15:04:15

lots of internal CLJS stuff add keys to objects

pinkfrog15:04:55

I’d expect the message field should exist in the (js-keys) output.

lilactown15:04:22

just testing this in the JS console

> let e = new Error("hi")
< undefined
> Object.keys(e)
< [] (0)

lilactown15:04:33

> e.message
< "hi"

lilactown15:04:08

my guess is that the message field on error objects aren't enumerable

pinkfrog15:04:01

That is said. This makes inconvenient to know what fields an object contains.

lilactown15:04:24

you can use Object.getOwnPropertyNames to see non-enumerable keys

lilactown15:04:32

> Object.getOwnPropertyNames(e)
< ["message", "line", "column", "stack"] (4)
typically there's a reason that fields wouldn't be enumerable. tbh I do not know why these fields aren't on errors

lilactown15:04:17

:thinking_face: it would be nice of CLJS protocol properties were non-enumerable, perhaps?

1
pinkfrog15:04:13

I have a general question on js introspection. How do you introspect a js object returned from an external library, it could be a normal js object, or it also be an instance of a class. Are you using Object.getOwnPropertyNames in the repl to introspect. If so, isn’t that too many chars to type?

p-himik15:04:06

Given your other questions, you're probably asking about React Native specifically, because when it comes to browsers it's really easy - just output an object to the JS console or view it as a local when the execution is paused in the debugger. I have never had to deal with RN, but surely it has some similar or maybe even the same tools. This page does seem to suggest it: https://reactnative.dev/docs/debugging#debugging-on-a-device-with-chrome-developer-tools

👍 1
zhuxun216:04:30

What do you guys use to minify/inline static resources (like index.html, main.css etc.) in a tools.deps + shadow-cljs setup?

zhuxun216:04:53

I guess a more general question is, how to build a packing pipeline (a la webpack) that can use arbitrary command-line tools, while monitoring all file changes in a folder?

zhuxun216:04:26

In the past, some suggested using webpack along with shadow-cljs. Is that still the best practice?

1
p-himik17:04:24

Not sure what you mean by "minify/inline" when it comes to index.html. Regarding reloading index.html - safer and easier to just refresh the page. Regarding CSS - you can make shadow-cljs reload it: https://shadow-cljs.github.io/docs/UsersGuide.html#_css_reloading And you can use build hooks to minify it in production or compile SASS/SCSS/LESS into CSS or whatever else you might need. And if you need something more complex, personally I find writing manual scripts for it (babashka or maybe even plain bash) much simpler and even easier than using webpack.

👍 1
isak19:04:51

I use a script that launches shadow-cljs via the api, and also starts a webpack watch. This way, there is only one command to use when starting the front end build watching for development.

lilactown18:04:17

when I use e.g. postcss I just run a separate watch command that runs postcss on changes to the filesystem

👍 2