loader() is the route data-fetching API for pages and layouts.
It works the same way during SSR and during client-side navigation, and it returns a handle with data, error, isLoading, and load().
import { loader } from 'eclipsa'
const useProfile = loader(async () => {
const response = await fetch('https://example.com/api/profile')
return response.json()
})
export default function Page() {
const profile = useProfile()
if (profile.error) {
return <p>Failed to load profile.</p>
}
return <pre>{JSON.stringify(profile.data, null, 2)}</pre>
}
A loader handle such as useProfile() exposes:
data: loaded data, or undefined if not loaded yet
error: the current error, if any
isLoading: whether a request is in flight
load(): a function that reloads the data explicitly
If the data depends on the route URL, read params from the request context.
import { loader } from 'eclipsa'
const useArticle = loader(async (c) => {
const slug = c.req.param('slug')
const response = await fetch(`https://example.com/api/articles/${slug}`)
return response.json()
})
export default function Page() {
const article = useArticle()
return <article>{article.data?.title}</article>
}
Call load() when the user should be able to refresh the data manually.
import { loader } from 'eclipsa'
const useClock = loader(async () => {
const response = await fetch('/api/time')
return response.text()
})
export default function Clock() {
const clock = useClock()
return (
<div>
<p>{clock.data}</p>
<button onClick={() => void clock.load()} disabled={clock.isLoading}>
Refresh
</button>
</div>
)
}
Loaders can also use middleware. This is useful for adding shared request metadata or auth-related state.
import { loader, type LoaderMiddleware } from 'eclipsa'
const requestMeta: LoaderMiddleware<{
Variables: {
traceId: string
}
}> = async (c, next) => {
c.set('traceId', crypto.randomUUID())
await next()
}
const useProfile = loader(requestMeta, async (c) => {
return {
traceId: c.var.traceId,
}
})
Values written with c.set() in middleware are available as c.var inside the handler.
Loaders are used in both cases:
Initial SSR
Reloads after client-side navigation
Because the API stays the same, page code usually does not need to care when the loader ran.
Loaders should return public data values such as:
strings
numbers
booleans
plain objects
arrays
They are not meant to return Response or ReadableStream directly.