Skip to main content
Not yet stable
@foresightjs/react is at 0.1.0 and not yet stable. It works and is fully tested, but the API may still change.
Version: 4.0

Foresight component

Foresight is the component form of useForesight: one instance, one registration. It renders in one of two ways.

Rendering an element with as

With as, Foresight renders that element itself and registers it. All other props are forwarded to the element:

import { Foresight } from "@foresightjs/react"

function CheckoutButton() {
return (
<Foresight as="button" callback={() => prefetch("/checkout")} onClick={checkout}>
Checkout
</Foresight>
)
}

as accepts any element tag ("button", "a", "div", ...) or a component that forwards its ref to a DOM element.

note

In the as form there is no way to pass your own ref to the rendered element, Foresight uses the ref slot for its registration. If you need the DOM node, use the render-prop form below and attach both refs yourself.

Styling with data attributes

In the as form, Foresight mirrors the element state onto data attributes — by mutating the DOM directly, without re-rendering the component:

  • data-predicted — present while isPredicted is true
  • data-callback-running — present while the callback is executing
  • data-status"success" or "error" after the last callback run

This makes prediction styling pure CSS:

button[data-predicted] {
outline: 1px solid orange;
}

Or with Tailwind:

<Foresight as="button" callback={() => prefetch("/checkout")} className="data-predicted:outline-1">
Checkout
</Foresight>

Reading state in as form

To use the reactive state in this form, pass a function as children, className or style — it receives the state. Foresight only subscribes to state-driven re-renders when one of them is a function:

<Foresight
as="button"
callback={() => prefetch("/checkout")}
className={({ isPredicted }) => (isPredicted ? "predicted" : "")}
style={({ isCallbackRunning }) => ({ opacity: isCallbackRunning ? 0.5 : 1 })}
>
{({ hitCount }) => <>Checkout ({hitCount})</>}
</Foresight>

For full control over the rendered markup, use the render-prop form below or useForesight.

Render-prop form

With a function as children, Foresight renders nothing itself. The function receives the reactive state plus the elementRef to attach, which gives full control over the markup:

import { Foresight } from "@foresightjs/react"

function CheckoutButton() {
return (
<Foresight foresightName="checkout" callback={() => prefetch("/checkout")}>
{({ elementRef, isPredicted }) => (
<button ref={elementRef} className={isPredicted ? "predicted" : ""}>
Checkout
</button>
)}
</Foresight>
)
}

In this form the data attributes are not set — you own the element, so render them from the state if you want them.

Options

Foresight takes the same options as useForesight, passed as props. The only renamed option is name, on the component it is foresightName, so the HTML name attribute (on input, button, select, ...) falls through to the element like any other prop.

Dynamic lists

Foresight can be rendered in a loop, registering one element per item.

import { Foresight } from "@foresightjs/react"

function Nav({ links }: { links: { href: string; label: string }[] }) {
return (
<nav>
{links.map(link => (
<Foresight
as="a"
key={link.href}
href={link.href}
foresightName={link.label}
callback={() => prefetch(link.href)}
>
{link.label}
</Foresight>
))}
</nav>
)
}