what do you mean 'scope'? is that the same as redux's store?
scope in js means 'access to names', that is, a namespace, is that the same thing in cljs?
There's a similarity with what I'm asking and js scope. I'm asking about which components define and manage which pieces of state. Reframe uses a global scope. Redux uses tree-local scope. Etc.
I earlier gave an analysis of this matter which I claim is complete, each react component have 3 distinct states in might handle. 1. state that is displayed, this includes hardcoded values like text or hiccup/jsx/html/element tagname/attr , but it also includes state that is derived from external sources but still has to be displayed in some manner 2. state that is necessary for its internal functioning, logic, business imperatives, but it is not something that is directly driving the output, so this is not like a flag to show/hide, more like a bunch of pre-baked percentages to calculate a number, or numbers/functions that are used to calculate positions, styles. 3. state that it has to send to third part, typically your own backend but also any other public services has some expectations on what it needs and that is under this category I don't believe that there is need for more categories here, and so far no one has tried to point out any state that is not under either of those (would be interesting to see such an example though!) Without further rules over how your components are built, potentially any react component can have any or all of these, what makes little sense to have a component that has neither.
Although this is still not the most useful probably, but it helps me to see what I am doing if I can put them in their right place since they usually are read and written at the same place/time
Sometimes I try to omit one (usually the last one) and it's always a mess đ
I am not experienced with cljs, but I expect these could have their own namespace/spec/tests and the rest of the app should use them, but since I am coming from js where circular dependencies are sometimes ok, it's probably not going to work just as easily
it also don't really make sense to me to use a different namespace's values in a simple react component, but I guess this is more just aesthetics, react is allowing "too simple" constructions that are not complex enough to be useful, but are simple enough to start out looking very promising and very neat
Now, you can put either of these three into either local or global scope, 1. 2. people don't really like in global, but then 3. is never this explicit, if you try to make just that global then you need some kind of system to connect the two
we at work use a custom js react hook called useElmish that mimics the Elm architecture
but any effector system that decouples effects from dispatches is fine, so your state updates are pure, I am probably getting overly detailed, so I stop đ
@lilactown found out yesterday what you meant when you said macros canât return macros. I thought I had some clever way of doing it by having a component functions return syntax quoted data and then having a render macro expand them, but all of the ways I tried couldnât that to work, always some nested form that wasnât evaluated. I guess now I know why Helix works the way it does đ
A macro can return a call to a macro though
Which will continue to be expanded further
that is true. what Iâve attempted before (and ran into issues) is macros defining other macros, e.g.
(defnc my-component [])
would create a new macro my-component
in the namespace. doesnât work in CLJS due to macros needing to exist in a CLJ namespace
But ya, no higher order behavior with macros. You can't return one and say pass it around to something else to use.
Hum, ya that's interesting. ClojureScript does throw additional ranches into it
@didibus but if the macro symbol that was returned is dynamic couldnât get it to work
considered trying eval but thatâs not bundled by default in cljs
Ya that's the ClojureScript limitation (I believe). All macros must be expanded at compile time, and in ClojureScript, compile time can not be interleaved with runtime.
honestly what Iâm trying is something i feel should work but i figure doesnât because of extra Clojurescript caveats
just to get it off my mind iâll put it here
like lets say this is inside a macro (
component props)`
where component
can be a function or a macro, important bit is that it returns more macro data, i.e. (compiler props children)
it seems like since component
was dynamically called, even though compiler
is a macro itâs not expanded and so in clojurescript runtime iâm just left with that unevaluated s-expression
I donât know if you can pass in a macro as a value like that
it works for another use-case I tried that was one level deep, but here i think because itâs a macro/function call that outputs more macro data (2 levels deep), couldnât get it to work
hmm yeah I just tested this: (defmacro foo [] âasdfâ) (defmacro bar [s] `(~s)) (bar foo) ;; => âasdfâ
thatâs in self-hosted CLJS tho - Iâm on mobile using Replete
That piece of code, it doesn't make sense
You're escaping all the unquote. You might as well write (component props)
those are dynamic arguments (wasnât a full example, just for sake of discussion)
Ah ok, also, ya I'm wrong as well. It does delay the function call till later
What do you mean here by dynamically called?
I suspect it might be the unquote qualified expansion that is messing it up
I'm also testing in self hosted replete though :p so can't say for sure
But I think unquote expands to a ClojureScript namespace
But your component macro has a Clojure namespace
What if you fully qualified it to the exact Clojure macro?
no the issue wasnât that it wasnât being called (example @lilactown posted for example works)
the issue was that the output wasnât being called
so say (~component ~props)
expands to (my-component {})
and thatâs a function that once called outputs (compiler {} children)
.. that last part, compiler
, is also a macro that I want macroexpanded
2 levels deep, not one
Oh, but with a function in the middle? Ya that won't work
Because the function will evaluate later, after the JS has already been compiled
yea thatâs what Iâve learned. but the necessary info is available at compile time so I was hoping it would work
So compiler is treated like a function by ClojureScript as well, and then you'll just see the return value of unquote
Well, why not make my-component a macro?
same result
Or return `(compiler component ~props)
hmm i didnât try that
kinda reluctant to try lol, working with cljs macros sucks up so much time
going to try it later and let you know if it works, thanks for suggestion @didibus
Ya macros in cljs are extra confusing.
Though I'm really surprised that 2 level deep macros didn't work, feel that should for sure work
is macro expansion expected to be recursive? i.e. macro outputs another macro s-expression, so the output is* also macro-expanded? i know it technically could work (info available at compile time) but figured itâs just not allowed
thinking about it, idt this would work since I need to access to that args that are closed in inside the component
function
It is ya
Outer macros expand first, and then it recursively expands until there are no more macros
So the outer macro expands, and the code it returned is then also macroexpanded, etc.
At least in Clojure
this is a simpler alternative that shows a summary of issue with nested macros in code
(defmacro defnc "Create component with given `tag` name and `body`."
[tag _bindings & body]
`(defmacro ~tag [props#]
;; This nested expression needs to be syntax quoted so we can pre-compile props
;; But since it is two levels deep then it isn't evaluated as cljs code by the Clojure compiler.
;; So at runtime, rather than having a fn call that creates a js object, we have a list of Clojure data.
`(.createElement react Fragment ~props# ~~@body)))
so even if we can call nested macros dynamically, their nested output isnât actually evaluatedyea thatâs how it works if the syntax quoted macro definitions are static, but not sure if thatâs meant to work if they are dynamic
In Clojure it would, because macros can expand at run-time as well
But not in cljs
Though I feel even on ClojureScript, nested macros in macros should still expand recursively at compile time
Try with clojure.core/defmacro