Skip to content

Instantly share code, notes, and snippets.

@basham
Created May 5, 2023 15:17
Show Gist options
  • Save basham/1874b7420de98312a75dcb4112d70ae5 to your computer and use it in GitHub Desktop.
Save basham/1874b7420de98312a75dcb4112d70ae5 to your computer and use it in GitHub Desktop.
Integrate Lit's reactive controllers with React.
import { useEffect, useReducer, useRef } from 'react';
export class Controller {
#host;
constructor (host) {
this.#host = host;
host?.addController(this);
}
update () {
this.#host?.requestUpdate(this);
}
}
export function useController (Ctrl, ...args) {
const [, requestUpdate] = useReducer((x) => x + 1, 0);
const controllers = useRef(new Set()).current;
const addController = (controller) => controllers.add(controller);
const removeController = (controller) => controllers.delete(controller);
const callControllers = (property) => controllers.forEach((controller) => {
if (property in controller) {
controller[property]();
}
});
const host = { addController, removeController, requestUpdate: throttleRAF(requestUpdate) };
const controller = useRef(new Ctrl(host, ...args)).current;
useEffect(() => {
callControllers('hostConnected');
return () => callControllers('hostDisconnected');
}, []);
callControllers('hostUpdated');
return controller;
}
// Call the function at most once per animation frame.
function throttleRAF (fn) {
let wait = false;
return function (...args) {
if (wait) {
return;
}
wait = true;
window.requestAnimationFrame(() => {
fn.call(this, ...args);
wait = false;
});
}
}
@basham
Copy link
Author

basham commented May 5, 2023

This follows most of the APIs outlined in the Lit Reactive Controller documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment