-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[labs] Reactive controller adapters for other frameworks #1682
Description
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
🆘 = 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>
);
};Metadata
Metadata
Assignees
Labels
Type
Projects
Status