Comments (3)
One thing to consider is this would conflict with CLJS.core/use and also editors may not indent it nicely by default.
from helix.
An alternative proposal:
- provide
with-deps
macro which- does code analysis
- (and maybe does some dev-time checks)
- name helix hooks in style
use-effect
oruse-memo
and let them take deps as first arg (current impl) - user implementing custom hook should name it
use-my-custom-hook
and put:helix/hook
meta flag on it, it is a normal function which can call other hooks usingwith-deps
, it can use passed-in deps to construct derived deps as needed
Examples:
; using a built-in hook
(with-deps :auto
(hooks/use-memo
(foo)))
; using a custom hook is no different
(with-deps [dep1 dep2]
(use-my-custom-hook
(foo)))
; implementing a custom hook
(defn ^:helix/hook use-my-custom-hook [deps f]
(let [new-deps (concat deps [dep3 dep4])]
(with-deps new-deps
(hooks/use-effect
(f)))))
; what if somebody does this?
(with-deps :auto
(println "some arbitrary code")
(hooks/use-memo
(foo d1))
(println "some other code")
(hooks/use-effect
(bar d2 d3)))
Let's discuss the last example. TL;DR; it should still work.
with-deps
macro should do deep walk of the body code and detect calls to hooks (it should look at the :helix/hook
metadata).
Each use-hook call will be rewritten, like in the current implementation (including optional code analysis). Explicit deps or auto-inferred deps will be passed in as the first arg.
So the above example would rewrite roughly to something like:
(do
(println "some arbitrary code")
(hooks/use-memo
#js [d1]
(fn [] (foo d1)))
(println "some other code")
(hooks/use-effect
#js [d2 d3]
(fn [] (bar d2 d3)))
Drawbacks
If user forgets to wrap hook call in with-deps
it will lead to non-sensical compilation errors. We could mitigate this with two changes:
with-deps
would not pass deps as the first arg, but bind it as a dynamic var (defaults to:auto
or:only
?)- use-hook bodies should be normal anonymous functions,
with-deps
would still analyze them, but not wrap them in to(fn [] ...)
Alternatively instead:
- dynamic var would be unbound by default, built-in hooks would have a detection that the deps are not set and would warn/error appropriatelly, this would still require use-hook bodies to be real functions.
This way even forgetting with-deps
would work and behave just like :auto
.
Ah, nah. The default must be :only
because without with-deps
no code analysis could run.
Further ideas
- allowing
with-deps
to be nested? - we could implement advanced code analysis in
defnc
, which would walk whole body and warn/error on hook usages behind conditional code
from helix.
I like the idea of moving hooks deps detection to the defnc
macro and a defhook
macro; the defhook
macro can do the work of annotating the custom hook var with necessary metadata to determine how to analyze the hook, and analyzing hooks within the custom hook body.
I have been working on code analysis inside defnc
body, detecting hooks usages in conditionals and loops. It's still very WIP, but can be activated in master by using a feature flag.
I think I am less bullish on the auto-deps functionality than I was before. I am more interested in detecting when deps are not filled in fully, and warning (with the ability to ignore). I am fine with not extending :auto-deps
for all hooks as long as we can extend the analysis of deps to all hooks.
from helix.
Related Issues (20)
- Some way for defnc to generate capitalized function names? HOT 5
- Infinite loop with IStateUpdater HOT 1
- "Provider" property access getting mangled by :optimizations :advanced HOT 5
- Remove es6 mention from readme HOT 1
- Update README to use React 18 createRoot api
- No dependency named react-dom/client HOT 3
- Confusing syntax with `wrap` and args destructuring HOT 1
- goog.object/extend is deprecated
- Setup cljstyle config, run in CI
- Any good way to make multimethods work as component functions? HOT 8
- gensym / anonymous function syntax breaks fast refresh HOT 2
- Include resources in deps.edn :paths
- $ clj-kondo hook fails to lint & right when component is not a symbol
- The $ macro and new JSX transform HOT 14
- `wrap-fx` is public HOT 1
- Wrappers for useTransition, useDeferredValue, etc. HOT 1
- Is it possible to bypass the camel-casing of properties? HOT 7
- Add wrapper around createRef with atom protocols HOT 2
- How to use with uikit? HOT 2
- Running tests in nodejs with jsdom HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from helix.