We would like to enable a framework-agnostic subset of reactive controller to work across frameworks. To do this we need two things from the frameworks: a way to emulate or map the framework lifecycle to the reactive controller lifecycle, and a native composition API or way to extend the framework component model to make adding controllers possible.
Many frameworks seem to have the basic lifecycle required by reactive controllers: hostConnected, hostDisconnected, hostUpdate, hostUpdated, and host.requestUpdate() - or they can be emulated. Not all have a way of extending the component model though
| Lifecycle |
React hooks |
Angular |
Vue |
Ember |
Svelte |
| hostConnected |
✅ initial render |
✅ ngAfterContentInit |
✅ onMounted |
✅ init |
✅ onMount |
| hostDisconnected |
✅ useLayoutEffect |
✅ ngOnDestroy |
✅ onUnmounted |
✅ didDestroyElement |
✅ onDestroy |
| hostUpdate |
✅ hook body |
✅ ngOnChanges |
✅ onBeforeUpdate |
✅ willUpdate |
✅ beforeUpdate |
| hostUpdated |
✅ useLayoutEffect |
✅ ngAfterContentChecked |
✅ onUpdated |
✅ didUpdate |
✅ afterUpdate |
| requestUpdate |
✅ useState |
⚠️ not needed w/ zones? |
✅ getCurrentInstance().update() |
⚠️ ? |
✅ writable store |
| updateComplete |
✅ useLayoutEffect |
✅ ngOnChanges w/ Promise |
✅ nextTick |
⚠️ ? |
✅ tick |
Composition or Extendable |
✅ custom hook |
✅ mixins |
✅ composition API |
⚠️ ? Mixin or CoreObject? |
✅ lifecycle hooks and stores |
| PR / Prototype |
#1532 |
Prototype |
Prototype |
|
Prototype |
✅ = There's a way to emulate
⚠️ ? = Unsure how to implement, but there's probably a way
🆘 = Seems like there isn't a way to emulate
We would like the mapping or controller wrapper to end up being as idiomatic as possible in the host framework. If the framework already has a composition API, like React hooks, we want to wrap reactive controllers into that API. If the framework doesn't have a similar API, then we could try to extend the component model with a subclass or mixin and add a way to declare controllers.
See #1532 for an example of creating a useController() hook for React that emulates and drives the reactive controller lifecycle. After wrapping a reactive controller with useController(), the resulting hook is used like any other hook:
Definition:
import * as React from 'react';
import {useController} from '@lit-labs/react/use-controller.js';
import {MouseController} from '@example/mouse-controller';
export const useMouse = () => {
const controller = useController(React, (host) => new MouseController(host));
return controller.position;
};
Idiomatic usage:
import {useMouse} from './use-mouse.js';
const Component = (props) => {
const mousePosition = useMouse();
return (
<pre>
x: {mousePosition.x}
y: {mousePosition.y}
</pre>
);
};
We would like to enable a framework-agnostic subset of reactive controller to work across frameworks. To do this we need two things from the frameworks: a way to emulate or map the framework lifecycle to the reactive controller lifecycle, and a native composition API or way to extend the framework component model to make adding controllers possible.
Many frameworks seem to have the basic lifecycle required by reactive controllers:
hostConnected,hostDisconnected,hostUpdate,hostUpdated, andhost.requestUpdate()- or they can be emulated. Not all have a way of extending the component model thoughinitial render
ngAfterContentInit
onMounted
init
onMount
useLayoutEffect
ngOnDestroy
onUnmounted
didDestroyElement
onDestroy
hook body
ngOnChanges
onBeforeUpdate
willUpdate
beforeUpdate
useLayoutEffect
ngAfterContentChecked
onUpdated
didUpdate
afterUpdate
useState
not needed w/ zones?
getCurrentInstance().update()
writable store
useLayoutEffect
ngOnChanges w/ Promise
nextTick
Extendable
custom hook
mixins
composition API
Mixin or CoreObject?
lifecycle hooks and stores
✅ = There's a way to emulate
⚠️ ? = Unsure how to implement, but there's probably a way
🆘 = Seems like there isn't a way to emulate
We would like the mapping or controller wrapper to end up being as idiomatic as possible in the host framework. If the framework already has a composition API, like React hooks, we want to wrap reactive controllers into that API. If the framework doesn't have a similar API, then we could try to extend the component model with a subclass or mixin and add a way to declare controllers.
See #1532 for an example of creating a
useController()hook for React that emulates and drives the reactive controller lifecycle. After wrapping a reactive controller withuseController(), the resulting hook is used like any other hook:Definition:
Idiomatic usage: