4 ms·
I have a question, lack of dynamic scope in render functions is causing me major issues in making highly dynamic and complicated UIs in ClojureScript. I underst
by dustingetz 10y ago
I have a question, lack of dynamic scope in render functions is causing me major issues in making highly dynamic and complicated UIs in ClojureScript. I understand that Javascript doesn't have proper dynamic scope so you guys probably weren't thinking about it, but I also see you guys moving farther and farther away, there's the whole Context hacks and now the web worker call stack serialization thing. Are there technical reasons that this can't be made to work with dynamic scope? I think you lose a lot of stuff by, well, not being actual function composition, only pretending to be.
cljs.user=> (ns foo.core (:require [reagent.core :as reagent]))
nil
foo.core=> (def ^:dynamic *foo* 42)
#'foo.core/*foo*
foo.core=> (defn inner [] [:div *foo*])
#'foo.core/inner
; React component call - broken
foo.core=> (defn root1 [] (binding [*foo* (inc *foo*)] [inner]))
#'foo.core/root1
foo.core=> (reagent/render-to-string [root1])
"<div ...>42</div>"
; Direct function call - works
foo.core=> (defn root2 [] (binding [*foo* (inc *foo*)] (inner)))
#'foo.core/root2
foo.core=> (reagent/render-to-string [root2])
"<div ...>43</div>"
A quick example of dynamic scope:
cljs.user=> (def ^:dynamic *foo* 42)
#'cljs.user/*foo*
cljs.user=> (defn negate [x] (- x))
#'cljs.user/negate
cljs.user=> (binding [*foo* (inc *foo*)] (negate *foo*))
-43
- spicyj 10y agoI don't know much Clojure, but it sounds like this is exactly the use case that context is meant for. If you were to use dynamic scope, how would the variables be restored if one of the descendants updated via setState? It doesn't seem to me like it would work. Also, not sure what "context hacks" you mean or what "web worker call stack serialization" is.
- dustingetz 10y agoI think dynamic scope can work with setState by allocating a new closure that closes over the dynamic vars, aliasing them into lexical scope of the render function. The problem with React Context is that it bypasses the general solution offered at language layer for a react-specific solution, essentially breaking any code written without prior knowledge of React.
- spicyj 10y agoCan you say what changes would be required in React for this to work? I assume that you are asking for parent components to be on the stack when child components render, but that is simply not how React works – you return a description of what you want to render then React calls into the children. How could the parent be on the stack? If you have a concrete suggestion for something we could change in React I'd be happy to chat about it. I'd love to support CLJS better.
- dustingetz 10y ago> but that is simply not how React works ... React calls into the children That's not how function components work, and i can easily imagine how to get lifecycle methods back (including optimizations) on function components
- spicyj 10y agoPlease open an issue with more details about the changes you'd like and tag me in it.