docs/solutions/performance-issues/2026-05-18-slate-extension-oncommit-should-keep-snapshot-lazy.md
Slate v2 moved extension authors from positional commitListeners to object-context
onCommit. A naive wrapper would call the internal two-argument listener shape
and force a snapshot even when the author only reads commit.
onCommit({ commit }) looked cheap at the public API layer.(commit, snapshot) through to every onCommit wrapper. That keeps
the old listener mechanics but defeats the snapshot laziness built into
notifyListeners.onCommit and a second no-snapshot callback.
That would make the public API look split again.Keep the internal listener arity at 1, and expose snapshot as a lazy getter on
the public context:
registerCommitListener(editor, (commit) => {
let snapshot: ReturnType<typeof getSnapshot> | null = null
slots.onCommit?.({
commit,
editor,
get snapshot() {
snapshot ??= getSnapshot(editor)
return snapshot
},
} as EditorCommitContext<TEditor>)
})
That lets normal handlers stay cheap:
onCommit({ commit }) {
exportCommit(commit)
}
and keeps snapshot access available when it is actually needed:
onCommit({ snapshot }) {
cacheChildren(snapshot.children)
}
notifyListeners already uses listener arity to decide whether it should compute
the snapshot for commit listeners. A one-argument wrapper preserves that fast
path. The getter computes the snapshot only if author code reads it, and caches
the result for repeated reads inside the same callback.