Skip to content

Instantly share code, notes, and snippets.

@Westbrook
Last active September 3, 2023 23:18
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Westbrook/bf27c6e5fc66c9c559b8e680ad9648a1 to your computer and use it in GitHub Desktop.
Save Westbrook/bf27c6e5fc66c9c559b8e680ad9648a1 to your computer and use it in GitHub Desktop.
useEffect() for `LitElement`... because everyone's doing it?
import {LitElement, html} from '@polymer/lit-element';
import {UseEffectMixin} from './use-effect.js';
class MyElement extends UseEffectMixin(LitElement) {
static get properties() {
return {
mood: {type: String},
expression: {type: String}
}
}
constructor() {
super();
// useEffect() with set up and cleanup.
this.useEffect((props) => {
let {mood} = props;
console.log('effect', mood);
return () => {
console.log('cleanup', mood);
}
});
// useEffect() with a property change gate
this.useEffect(() => console.log(this.mood), ['expression']);
// useEffect() for firstUpdated() and disconnectedCallback()
this.useEffect(() => {
console.log('first');
return () => console.log('last');
}, []);
}
render() {
return html`
<style> .mood { color: green; } </style>
A ${this.expression} sort of ${this.mood}.
`;
}
}
const hasRecentlyConnected = Symbol();
const effects = Symbol();
const cleanups = Symbol();
const cleanupsDisconnected = Symbol();
const cleanup = Symbol();
const UseEffectMixin = (base) => {
return class extends base {
[effects] = [];
[cleanups] = [];
[cleanupsDisconnected] = [];
connectedCallback() {
this[hasRecentlyConnected] = true;
super.connectedCallback();
}
disconnectedCallback() {
super.disconnectedCallback();
this[cleanups] = this[cleanup](this[cleanups]);
this[cleanupsDisconnected] = this[cleanup](this[cleanupsDisconnected]);
}
updated(changedProperties) {
super.updated(changedProperties);
this[cleanups] = this[cleanup](this[cleanups]);
this[effects].map(({effect, tests}) => {
if (tests && ((!tests.length && !this[hasRecentlyConnected]) || !tests.every(test => changedProperties.has(test)))) return;
const cleanup = effect(this);
if (cleanup && (!tests || tests.length)) this[cleanups].push(cleanup);
else if (cleanup) this[cleanupsDisconnected].push(cleanup);
});
this[hasRecentlyConnected] = false;
}
[cleanup](cleanups) {
cleanups.map(cleanup => cleanup());
return [];
}
useEffect(effect, tests) {
this[effects].push({effect, tests});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment