Comments (8)
React components must be either a literal JavaScript function, or an object that inherits from the React.Component
class. Unfortunately, multi methods do not fall into those categories.
I would recommend structuring your code in a way that the business logic is handled by multi method, but the component itself is a function. Similar to your examples:
(defmulti animals :animal)
(defmethod animals :dog
[]
"rendering dog")
(defmethod animals :sheep
[]
"rendering sheep")
(helix/defnc using-multimethod
[]
(helix/$ :div (animals {:animal :dog})))
While less powerful than using the multi method as a component itself, this protects you from a potential footgun: if your multicomponent used hooks, and the :animal
passed in changed, it could render new hooks or need to re-initialize them based on the method used and React wouldn't know how to do that, because the identity of methods are the same no matter the branch it takes. It would be akin to:
(defnc my-multi-component
[{:keys [animal]}]
(case animal
:dog (let [[barked? set-barked] (hooks/use-state false)]
,,,)
:sheep ,,,))
This is breaking the rule where hooks should never be conditionally used inside of a component.
from helix.
I appreciate the good discussion @simonacca :)
from helix.
Wow, thank you, I didn't consider the hook problem at all!!
I still belive it would be great to get multimethods working in this particular case as I'm using them to implement lazy-loaded plugins (so both the business logic and the components are loaded just in time when the application calls for a particular plugin).
As a last attempt, what are your thoughts on using the multimethod's dispatch-val
(that is, :dog
, :sheep
and the like) as a React key to "force" React to realize that they are indeed different components?
Proof of concept:
(defmulti animal
(fn [props] (.-animap props)))
(helix/defnc multimethod-wrapper [{:keys [mm] :as props}]
(helix/$ (fn [inner-props] (mm inner-props))
{:key ((dispatch-fn mm) (helix.impl.props/-props props))
:& props}))
(helix/defnc using-multimethod
[]
(helix/$ multimethod-wrapper {:mm animal :animal :dog}))
p.s. I suppose the anonymous function in multimethod-wrapper
should be memoized...
from helix.
How exactly do you implement lazy-loading this way? I'm interested to learn.
from helix.
Using shadow-cljs's built-in loader. In practice:
- Define multimethod in one namespace
- Define plugins one per namespace, as methods of the above multimethod
- Define each plugin as a separate module in the config
- At runtime, make sure to load each module using
shadow.loader
before it is rendered
from helix.
Have you looked at React.lazy and [shadow.lazy], as described in thheller's blog post on code splitting?
With a bit of macro magic you can lazily load individual components really easily.
;; a lazy-loaded about page
(def about (lazy town.lilac.app.about/page)
(defnc routes
[]
(case (use-route)
:home ($ home)
:about ($ about)))
(defnc app
[]
(d/div
($ navigation)
(helix/suspense
{:fallback ($ spinner)}
($ routes))))
This way, you can render a fallback spinner if the module hasn't been loaded yet and is taking awhile. I'm not sure how you would do this with the multi method approach.
from helix.
Very interesting, didn't know about either shadow.lazy
nor React.lazy
, thank you!
Youst to continue the theoretical exercise, if one still wanted to use multimethods, they could for example:
- implement the spinner as the
:default
method - tweak
multimethod-wrapper
to perform the lazy loading in an effect and trigger a rerender when loading has occurred
In any case, it seems clear (in my view at least) that there is nothing to change in helix per se stemming from this conversation, therefore am closing the issue. Should you have a different opinion, please feel more than welcome to reopen.
Thanks again!
Simon
from helix.
Likewise!
from helix.
Related Issues (20)
- 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 HOT 1
- 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
- Companies using Helix HOT 1
- indent metadata on helix.dom macros HOT 3
- Create use-isomorphic-layout-effect HOT 6
- Make self-hosted CLJS compatible HOT 2
- Fix indentation with CIDER HOT 3
- Release request HOT 1
- Warning: React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead. HOT 2
- `helix.dom/tags` removed HOT 2
- defnc taking pre- & post-conditions HOT 1
- Release request HOT 1
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.