onMount(props)
Work with the rendered DOM
onMount runs once after the first DOM render. Template refs, layout measurements, focus and third-party libraries belong here. A returned function is the cleanup, run on destroy.
onMount(props) {
this.state.name_input.focus()
const editor = new Editor({
element: this.state.editor_root,
})
return () => editor.destroy()
}
<input fez:this="name_input" />
<div fez:this="editor_root"></div>
refs point to connected, rendered elements
a throw in init, the first render or onMount is reported and the instance destroyed
afterRender()
React after every morph
This hook runs after the rendered HTML has been applied, and also when the render hash matched and the DOM was left alone. Use it for a small side effect that genuinely needs the latest DOM after every component render.
afterRender() {
this.root.style.setProperty(
'--rows',
this.root.querySelectorAll('li').length
)
}
DOM morphed--rows: 6 applied afterward
avoid state writes here unless a second render is intentional
onRefresh(props, changed)
Know when a parent preserves you
onRefresh runs after mount and whenever this instance is kept and handed props: by a parent render, a pjax or Fez.nodeMorph swap, or fez-component. changed holds the props whose value differs (every prop at mount). The child already re-rendered for a changed prop. It does not fire for the child's own state render or for outside DOM events.
onRefresh(props, changed) {
if ('revision' in changed) this.load()
}
parent morphedchild instance stayed connected
use this.on for document, window and Pjax events
onStateChange(key, value, oldValue)
Observe local state writes
Runs when reactive local state changes, with the top-level key and old and new values. The pending UI render remains batched into the next frame.
onStateChange(key, value, oldValue) {
if (key === 'count') {
this.globalState.max = Math.max(
value,
this.globalState.max || 0
)
}
}
count: 2 → 3global max becomes 3
nested writes report through their owning top-level state key
onGlobalStateChange(key, value, oldValue)
Observe shared state
Components that read a global key receive this hook synchronously when that key changes. A key the last render read also schedules one render alongside any local state changes; a key read only in code, as below, fires the hook alone.
init() {
this.globalState.theme // subscribe by reading
}
onGlobalStateChange(key, value, oldValue) {
if (key === 'theme') {
document.documentElement.classList.toggle(
'dark', value === 'dark'
)
}
}
theme: light → darksubscribers update together
a component's own write during render does not schedule an extra pass
addOnDestroy() · onDestroy()
Release external resources
When MutationObserver sees the component disconnect, Fez runs callbacks registered with addOnDestroy(), removes listeners, observers, timers and subscriptions, then calls onDestroy for external resources.
onDestroy() {
this.state.editor?.destroy()
this.state.chart?.dispose()
}
onMount() {
const observer = new MutationObserver(this.track)
observer.observe(this.root, { childList: true })
this.addOnDestroy(() => observer.disconnect())
}
// already cleaned by Fez:
// this.on(...)
// this.setTimeout(...)
// this.setInterval(...)
// this.subscribe(...)
// this.observeResize(...)
// onMount and fez:use cleanups
listeners removedtimers clearedsubscriptions dropped
cleanup runs once, even if the node is removed more than once; a throwing onDestroy is reported and teardown completes
onError(error, component)
Error boundaries
Any ancestor that defines onError catches a descendant's mount error, render throw or template runtime error, with the failing instance as component. Set state to show a fallback, or throw to pass the error further up. Without a boundary, Fez.onError reports it as before; a failed template always keeps its last rendered DOM.
Try the context and boundary demo.
onError(error, component) {
this.state.error =
`<${component.fezName}> ${error.message}`
}
<risky-widget />
{#if state.error}
<p class="error">{state.error}</p>
{/if}
<risky-widget> failed to start
a child that fails to mount is destroyed; one that fails to render keeps its last DOM
this.context(key, value?)
Context down the component tree
this.context(key, value) provides a value; this.context(key) reads it from the nearest component up the tree, the caller included. Read it in init(). Context is not reactive: provide an object, or use globalState for values that change.
// provider
init() {
this.context('theme', { color: '#1f7a8c' })
}
// any descendant, however deep
init() {
this.state.theme = this.context('theme')
}
theme found 3 levels up
Svelte's setContext and getContext in one call