mitosis
mitosis copied to clipboard
Compile away hooks
Purely an idea, but something been thinking about a lot. One of the biggest missing DX features of Mitosis is custom hooks
Interestingly, some ppl have been exploring making hooks libraries across frameworks
If you think of someone building an app in Mitosis vs a framework like Qwik directly, you miss out on one of the main composability benefits, custom hooks. Such as a react-query like hook (called Resource in Qwik and Solids) etc. I can't see people loving building with Qwik without this key feature nearly all modern frameworks have (react, vue, svelte, qwik, solid) that Mitosis doesn't
I realized I think we can implement this for all hooks-oriented frameworks. We may even be able to implement it for frameworks without first class hooks support.
We could do it, for instance, with another convention just like we have .lite.tsx
for components, and .context.tsx
for context, we could make a .hook.tsx
// ./use-fetch.hook.tsx
import { useState, onMount } from '@builder.io/mitosis'
export default function useFetch(url: string) {
const [value, setValue] = useState(null)
const [error, setError] = useState(null)
const [loading, setLoading] = useState(false)
onMount(async () => {
setLoading(true);
try {
const data = await fetch(url).then(res => res.json())
} catch (error) {
setError(error)
} finally {
setLoading(false)
}
setValue(data)
})
return { value, loading, error };
}
which would compile to other frameworks just like you see in mitosis components name
I think translating hooks like this is pretty straightforward to everywhere that supports hooks. the big question is what about frameworks, like Angular, that don't. I have some crazy ideas for that but need to think on a little more
this as a feature could be useful standalone to those like tanstack too, to make hooks that support all hooks-oriented frameworks that you write once and it compiles out to all. and of course benefits mitosis components and libraries too
Fully agree, providing some form of "hooks" support is probably a critical next feature for Mitosis. It's been on my mind...folks need a way to encapsulate complex logic and reuse it across components. https://zagjs.com/ Does somewhat of the same thing as Tanstack (hooks lib tailored for finite state machines, with framework-specific bindings for React/Vue/Solid)
I think translating hooks like this is pretty straightforward to everywhere that supports hooks. the big question is what about frameworks, like Angular, that don't. I have some crazy ideas for that but need to think on a little more
Yeah, I'd want to lay out a rough plan outlining what this would look like in the most "important"/"relevant" 5-6 frameworks to ensure it would work in enough places (Vue/React/Svelte/Solid/Qwik). I see it working with none/very little work for react/svelte/solid, but also need to think a tiny bit about Vue. They have 2 different API styles now, there could be some quirks:
- https://vuejs.org/guide/introduction.html#api-styles
- https://vuejs.org/api/reactivity-core.html
Composition API is also Vue3 only I believe, so that's another thing to keep in mind.
Also concerned about how much additional scaffolding would need to go into making hooks work in webcomponents
/html
, which could lead to us potentially implementing a full web framework's features to get them to work.
Agree w/ all of that. And also currently don't think this is any level of priority but I have some vague ideas on how to support webcomponents/html/angularetc. Perhaps a little library could/would be needed. I could see that as an interesting project in general - framework agnostic simple hooks system that can plug into any framework that doesn't currently support it. This is a bit like how mobx works (and solidjs reactivity, etc). Not sure what tanstack and others do, I am assuming they just manually implement across but maybe they have a helper system we can draw inspiration from
But perhaps a little helper library one day is the ultimate solution. Support hooks for frameworks that support hooks (via direct compilation, no lib needed), and at some point someone can create a framework agnostic hooks primitive library that this could output to as well
Interesting to think of how a small library could bring hooks to angular and other frameworks. Could be interesting to those communities
Composition API is also Vue3 only I believe, so that's another thing to keep in mind.
FYI Vue 2.x supports the Composition API natively since 2.7 (released weeks ago). For earlier releases, you need the @vue/composition-api
plugin.
Vue 2.7 Composition API works like Vue 3 Composition API, except when otherwise noted.
@leopiccionia Thanks a lot for sharing, that's very valuable information!
Imagine VueUse working in all frameworks. That would be really nice.
I think it is very important to talk about what we are translating here. A lot of internal and external functions in frameworks have similar features that overlap, so let's get as precise as possible.
I am trying to find the simplest, most direct equivalents; some items on here can do all of these.
Passing data from parent to child
- React
props
- Angular
@Input
- Vue
props
- Svelte
export
These generally are just passing the data, no binding.
Passing data from parent to X grandchild
- React -
useContext
- Angular -
InjectionToken
withprovider
- Vue -
provide
- Svelte -
setContext
withgetContext
Passing data from child to parent
- React -
useState
withprops
- Angular -
@Output
withEventEmitter
- Vue -
$emit
- Svelte -
createEventDispatcher
Basically the same thing for grandchildren:
Passing data from X grandchild to grandparent
- React -
useState
withuseContext
- Angular -
@Output
withEventEmitter
- Vue -
$emit
- Svelte -
createEventDispatcher
Sharing data with ANY component
- React -
Context.Provider
at the top level withuseContext
- Angular -
providers
at top level (modules or since v14 components), aka services (although not only type) - Vue -
provide
andinject
- Svelte -
stores
What are we really talking about here?
- Shared State - Providing a shared function or class at the top-level - whether it be a provider in a module--component or a context function that can be called from a child to keep state. Child components may need to evoke an emitter to push the DOM changes if necessary
- Caching computation - some functions like React's
useCallback
oruseMemo
can help with speed - Subscribing to changes -
useState
(React),rxjs observables
(all Javascript but mainly Angular), orstores
(Svelte)
There is really a weird combination of all three of these things in our frameworks, but they are by far the easiest to work with using Svelte Stores
, Angular Services
, and RXJS Observables
.
Other things to consider for this project:
- It could be cool to have a framework that could build an APP in any framework.
-
Routing
would be perhaps the only other core feature left to translate. - Everything should be translated to TypeScript. Don't make me get into this debate. It just should. Period.
- Everything should be SSR ready. Don't access the DOM directly.
It would be cool to build a basic app to see how similar and exact you could get these features --- a todo app for example.
J