Skip to content

Instantly share code, notes, and snippets.

@gordonbrander
Created March 6, 2023 13:39
Show Gist options
  • Save gordonbrander/01726958af83536370143941265fd2e0 to your computer and use it in GitHub Desktop.
Save gordonbrander/01726958af83536370143941265fd2e0 to your computer and use it in GitHub Desktop.
RenderingElement - A custom element that batches updates on animation frame
// RenderingElement
// A custom element that batches state updates on animation frame.
export class RenderingElement extends HTMLElement {
// Element state to render
#state = this.defaults();
// Has an animation frame been scheduled?
#isAnimationFrameScheduled = false
// Perform a render and flag that animationFrame has completed.
// Hard-bound so we can pass as a callback to requestAnimationFrame.
#frame = () => {
this.#isAnimationFrameScheduled = false
this.render(this.#state)
}
constructor() {
super()
this.attachShadow({mode: 'open'})
// Render initial markup
this.setup(this.#state)
}
// Set next state and schedule a render on next animation frame.
// Batches renders, so that if a render is already pending, it will
// just wait for that one.
state(next) {
this.#state = next
if (!this.#isAnimationFrameScheduled) {
this.#isAnimationFrameScheduled = true
requestAnimationFrame(this.#frame)
}
}
// Initial state
defaults() {
return null
}
// Set up element. Runs once, immediately upon construction.
setup(state) {}
// Render state.
// When you set `this.state(...)`, this will be called during the next
// animation frame.
render(state) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment