This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-05-20
Channels
- # aleph (11)
- # announcements (3)
- # babashka (35)
- # babashka-sci-dev (28)
- # beginners (29)
- # calva (51)
- # cider (33)
- # clj-kondo (26)
- # clj-on-windows (1)
- # clojure (40)
- # clojure-austin (1)
- # clojure-europe (47)
- # clojure-nl (9)
- # clojure-norway (7)
- # clojure-uk (5)
- # clojurescript (69)
- # conjure (30)
- # cursive (7)
- # data-science (9)
- # datomic (2)
- # etaoin (10)
- # events (2)
- # fulcro (1)
- # graalvm (1)
- # gratitude (6)
- # helix (16)
- # honeysql (20)
- # hyperfiddle (14)
- # inf-clojure (2)
- # jobs (1)
- # jobs-discuss (12)
- # kaocha (9)
- # leiningen (2)
- # lsp (4)
- # malli (8)
- # music (9)
- # off-topic (12)
- # pathom (10)
- # portal (14)
- # practicalli (15)
- # re-frame (27)
- # reitit (7)
- # remote-jobs (4)
- # sci (37)
- # shadow-cljs (16)
- # sql (8)
- # tools-deps (6)
- # vim (6)
- # xtdb (21)
What is the fastest and easiest way to build front end UI components using Clojurescript?
Shadow-cluster and reagent
maybe I'm beating a dead horse here and this is a silly question.. but would it make sense with an option to the cljs compiler that disabled minification for all JS interop? Most of my cljs are calls to my own code, it's only a handful of places where I call (.someMethod js-thing)
etc. with this "externs safe mode" you'd get (slightly?) larger output files, but the benefit of never having to deal with externs
lots of internal CLJS code does a lot of JS interop, basically everything is just JS interop in the end. so the trouble comes from not reliably figuring out what can and can't be renamed. definining "your calls" is the hard part here. if you use a macro that ends up generating interop calls, is that your code or not? đ
@emaun you'll have to look at the git logs - probably some kind of fix for some consumers
I have a Clojurescript app that uses Reagent with Preact instead of React. Everything works fine except Fragments, which for some reason I cannot access with react/Fragment
. Interestingly, I can (:import (react Fragment))
in the ns declaration and then use Fragment
in a (react/createElement Fragment etc)
call, or I can access Fragment
with object property syntax (.-Fragment react)
. I just can't access Fragment
using the normal syntax for referencing a var in a namespace, react/Fragment
. Anyone have a guess as to why this is happening?
I just tried this:
(ns ...
(:require ["react" :as react]
["preact" :as preact]))
(js/console.log "React's Fragment" react/Fragment)
(js/console.log "Preact's Fragment" preact/Fragment)
And it seems to be working fine, at least with shadow-cljs and the latest version of Preact.
What do you mean by "cannot access" exactly?Hi @p-himik, thanks for the reply. By "cannot access", I mean react/Fragment
is undefined
. I'm using a modified build of Preact, so clearly I've done something to create this situation. I'm curious what could cause a javascript "namespace" like preact to not work with the ns/function
syntax but work with (.-function ns)
.
I'm including preact and preact-compat as foreign libs in the clojurescript compiler config, and preact-compat :provides ["react", "react-dom", "create-react-class"]
.
The change to preact and preact-compat was to remove all the different module styles at the top (the original built script has support for ES modules, commonjs, and defining a global variable), and only leave in the global variable definition.
I require preact in my code as react because of the :provide config I'm using; (:require [react])
Also note I'm not using shadow-cljs, I'm calling the clojurescript compiler directly via clojure code.
> and only leave in the global variable definition But why? There being multiple modules shouldn't affect anything - in the end, only one of them is compiled in.
The multiple module definitions were present in the script after advanced compilation. I changed that code in an effort to shrink the script a bit more.
I'll have to check whether react/Fragment
works without those changes.
> The multiple module definitions were present in the script after advanced compilation That's... bizarre. I've never even heard about that, so maybe there's something else wrong in your setup. I'd try fixing that instead of bandaging it by changing your dependencies.
Just tried (with shadow-cljs, since I don't have a raw CLJS compilation set up) compiling an optimized build - there's only one reference to preact in there, to one file.
Ok, thanks for the help. I'll see if I can simplify the way I'm using the dependencies to avoid this issue.
Reagent folks, did you know you it's possible to use React hooks in your components by making them functional (instead of class components)? I thought I was late to the party, but am finding out that others also had no idea, so I wrote up a quick summary. Hope this helps someone! https://mmmanyfold.notion.site/Yes-you-can-use-hooks-in-Reagent-c1747078e27644e0ab2eb35e07fe6922
You could use hooks even before :f>
. :)
Also, I'd recommend making that (fn [] ...)
in your article a proper defn
. It'll get a proper name, it will not be re-instantiated on each render of the parent component, it will work nicely with Reagent cache that way.
Thanks @U01B301AJV8 ! it is still not anywhere mentioned in the docs unless you go digging for it, so thanks for calling it out
@p-himik if you could use hooks before :f>
then what value does it provide?
It is mentioned in the docs: https://github.com/reagent-project/reagent/blob/master/doc/ReactFeatures.md#hooks > if you could use hooks before :f> then what value does it provide? Easier usage of existing functional components. > why reagent doesn't provide a use-ratom hook so then :f> isn't needed Why wouldn't it be needed? Functional components can be used even when no hooks are used at all. Apart from that, there are many existing hooks - nothing new that Reagent can introduce would alleviate the need for functional components here.
> "mentioned in the docs unless you go digging for it"
but yes it is there. (but not here https://reagent-project.github.io/)
You don't need :f>
as :>
works - so you'd use use-ratom
inside a function and render it with :>
that was my point
> (but not here https://reagent-project.github.io/)
Because it's not a documentation website, it's a blog. :) But yeah, the docs could be improved and made more discoverable: https://github.com/reagent-project/reagent/issues/302
> so you'd use use-ratom
inside a function
What about every single hook that already exists out there? How would you use those?
I don't follow. Why wouldn't this work from Michelle's example:
(defn example []
[:> ;; <-- make pass through untouched
(fn []
(let [[count set-count] (react/useState 0)] ; <---
(react/useEffect ; <---
#(set! (.-title js/document) (str "You clicked " count " times"))
#js [checked])
[:div
[:p "You clicked " count " times"]
[:button {:on-click #(set-count (inc count))}
"Click me"]]))])
it's the same they mention in the docs https://cljdoc.org/d/reagent/reagent/1.1.1/doc/tutorials/react-features#pre-10-workaround
to make it concrete - what i'm thinking is making this part of the API as use-ratom
or similar
https://github.com/reagent-project/reagent/blob/9ddf191a6a7338d226161e8af0d7ecc0bc2a6bae/src/reagent/impl/component.cljs#L400
> Why wouldn't this work from Michelle's example:
Because it doesn't have a call to reagent.core/as-element
. The docs do mention it.
> it says you can't use RAtoms there - so that's my point -just make a hook
Not every reactive thing is a ratom. Cursors won't work there, as well as reactions, and tracks.
Instead of adding many things for every use case, wouldn't it be both simpler and easier to just add one :f>
, exactly as it is done now?
There might easily be other differences that I'm not aware of - specifically because :f>
is not just a wrapper around :>
. It has its own implementation, with its own logic.
yes, use-reagent
- my point is a hook that performs that integrates with reagent. Agreed you'd probably end up with :f>
at the end. Thanks for the discussion
I donât have a firm grasp on hooks, still learning react and reagent. But what is the #js [checked]
portion as the final argument in the call to react/useEffect
? I canât see where checked
is coming from, to my untrained eye it looks like a symbol that came out of nowhere.
@UTFAPNRPT that's a typo from a previous version of the example! it's supposed to be count
. thank you so much for catching it, fixed now
Great article Michelle! I actually didnât know that and Iâve been doing reagent/reframe for yearssss. I think youâre right that when things âarrive quietlyâ its easy to miss. Thanks for pointing out đ
I need some help in providing an async function to a security framework (Okta) ... how would one provide a CLJS equivalent of this?
const restoreOriginalUri = async (oktaAuth, originalUri) => {
history.replace(toRelativeUrl(originalUri || '/', window.location.origin));
};
the literal equivalent of this would be
(defn restore-original-uri [okta-auth original-uri]
(js/Promise.
(fn [res _rej]
(res (.replace js/history (toRelativeUrl (or original-uri "/") (.. js/window -location -origin)))))))
(but also I don't write modern JS with any regularity, so maybe I don't know this pattern)
https://stackoverflow.com/questions/69644106/reactjs-okta-auth-restoreoriginaluri-function-not-redirecting sums up the problem and the correct JS answer
It's completely valid JS https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function ... await
is not mandatory
> Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
anyways, there is an oddity which I can't find an answer to which that maybe async
will resolve promise arguments that news to me
I see, the SO question is just about not checking for null
that is all, async
does not magically resolve promise arguments
@raymcdermott To summarize the above, just write it as if there was no async
. Unless you need to use some async functionality inside the function - then just return a promise.
it might be that the API needs you to return a promise, and they are using async
here as syntactical shortcut
but couldn't find that out, and I don't have the patience to look at all this Okta docs
They're just using plain await
which works on any value, not just promises. And in the TS type definitions they explicitly say that they expect a function that returns a promise (which isn't actually needed).
@raymcdermott It's probably not applicable in your case, but beware of returning JS objects that have a field then
in them that points to a function. Due to the mess that JS is, such objects will be treated as implicit promises.
I recon there must be a good reason why the g
flag is not supported for ClojureScript regexes. But this gets a bit confusing:
(js/RegExp. "foo" "g")
=> #"foo"
(.replace "foo foo" (js/RegExp. "foo" "g") "bar")
=> "bar bar"
I am very happy this works (because re-seq
is not an easily available option for me right now), but anyway.