Skip to main content
Version: 4.0

Other Frameworks

There are official packages for React and Vue. For every other framework (Angular, Svelte, Solid, …) js.foresight has everything you need to build your own thin binding. This page shows the two pieces involved: registering from a component lifecycle, and the subscribe pattern for reactive state.

Registering from a component

Register the element when your component mounts and unregister when it is destroyed. Detaching an element from the DOM does not unregister it (it is parked and resumes if it reattaches), so the cleanup call matters. A Svelte action is a good example of the shape:

import { ForesightManager } from "js.foresight"

// <a use:foresight={{ callback: prefetch }} href="/about">About</a>
export function foresight(node, options) {
const { unregister } = ForesightManager.instance.register({
element: node,
...options,
})

return {
destroy: () => unregister(),
}
}

The options are the same registration options as everywhere else; callback is the only required field.

The subscribe pattern

If you only fire a callback, the snippet above is all you need. But register() returns more: the element's full state snapshot plus subscribe and getSnapshot. The state is an immutable snapshot whose reference is replaced (never mutated) on every change, which makes it plug into any reactivity system:

const reg = ForesightManager.instance.register({
element,
callback: () => prefetch("/about"),
})

const unsubscribe = reg.subscribe(() => {
const state = reg.getSnapshot()
element.classList.toggle("predicted", state.isPredicted)
})

// when the component is destroyed
unsubscribe()
reg.unregister()

subscribe(listener) calls your listener on every state change and returns an unsubscribe function. getSnapshot() returns the current snapshot, because the reference only changes when the state changes, equality checks are enough to know whether to re-render.

This is exactly how the official packages are built:

  • React feeds the pair straight into useSyncExternalStore(reg.subscribe, reg.getSnapshot).
  • Vue stores the snapshot in a shallowRef and replaces it inside subscribe.
  • Svelte (runes) is the same idea: keep the snapshot in $state.raw and reassign it inside subscribe.
  • Solid can wrap it with from(set => reg.subscribe(() => set(reg.getSnapshot()))).

If you build a binding for your framework, sharing it is highly appreciated!