pageContext.isHydration: Whether the page is rendered to HTML. When using Client Routing, the value is true for the first page the user navigates to, and false for any subsequent navigation. (When using Server Routing, the value is always true.) (If the page doesn't throw an error then it's equivalent to !pageContext.isClientSideNavigation, otherwise the error page is rendered and thus pageContext.isHydration is false whereas !pageContext.isClientSideNavigation is true.)
pageContext.isBackwardNavigation: Whether the user is navigating back in history. The value is true when the user clicks on his browser's backward navigation button, or when invoking history.back(). The isBackwardNavigation property only works with Client Routing. (The value is always null when using Server Routing.)
pageContext.previousPageContext: Upon client-side page navigation, you can use pageContext.previousPageContext to access the pageContext of the previous page. See Lifecycle.
pageContext.is404: If an error occurs, whether the error is a 404 Page Not Found or a 500 Internal Error, see API > Error Page.
pageContext.isClientSideNavigation: Whether the page was navigated by the client-side router. In other words, when using Client Routing, the value is false for the first page the user visits, and true for any subsequent navigation. (When using Server Routing, the value is always false.)
// Your Vike server middleware integrationapp.get('*', async (req) => { const pageContextInit = { urlOriginal: req.url, headersOriginal: req.headers, // *************************************** // **** Custom pageContext properties **** // *************************************** // Common use case: make information about logged-in user available at pageContext.user user: req.user, // Or any other value: // pageContext.someCustomProp someCustomProp: 'some-value' } const pageContext = await renderPage(pageContextInit) // ...})
Yes, it's a common practice to change/add pageContext properties at any time.
// AnywherepageContext.someProp = someValue
Can I use pageContext as a UI store?
Instead of using pageContext, we generally recommend using a proper UI state management tool such as React's useState(), Redux, Vue's ref(), Pinia, etc.
That said, there are use cases for using pageContext to store client-side state. For example to pass information from the previous page to the next during navigation.
See Lifecycle to understand whether using pageContext can make sense for your use case.
// +onAfterRenderHtml.jsexport function onAfterRenderHtml(pageContext) { const isSSR = !!pageContext.Page if (isSSR) { // ... }}
TypeScript
import type { // For code loaded in client and server PageContext, // For code loaded in client only PageContextClient, // For code loaded in server only PageContextServer} from 'vike/types'
To extend and/or refine Vike's types PageContext/PageContextServer/PageContextClient, use the global interface Vike.PageContext:
declare global { namespace Vike { interface PageContext { // Type of pageContext.user user?: { name: string id: string isAdmin: boolean } // Refine type of pageContext.Page (it's `unknown` by default) Page: () => React.JSX.Element } }}// If you define Vike.PageContext in a .d.ts file then// make sure there is at least one export/import statement.// Tell TypeScript this file isn't an ambient module:export {}
import type { // For code loaded in client and server PageContextWithServerRouting as PageContext, // For code loaded in client only PageContextClientWithServerRouting as PageContextClient, // For code loaded in server only PageContextServer} from 'vike/types'
Lifecycle
Server
On the server-side, upon an HTTP request, a new pageContext object is created. It's used for rendering the page to HTML. The pageContext object is discarded after the HTTP response is sent.
You can use pageContext.previousPageContext to access the pageContext of the previous page.
Pre-rendering
The server-side pageContext of a pre-rendered page is determined at build-time when the page is pre-rendered.
Each pre-rendered page has a pageContext object saved at dist/client/${url}/index.pageContext.json.
This means that, if the first page the user visits is a pre-rendered page, then the pageContext was already determined (potentially a long time) before the user visits that page.
Consequently, if the user visits the URL /products?filter=computer then pageContext.urlParsed.search is empty and ?filter=computer is missing.
In theory, Vike could update pageContext on the client-side and add ?filter=computer to pageContext.urlParsed but this would lead to a hydration mismatch. That's why, upon hydration, Vike intentionally keeps the client- and server-side pageContext aligned for hydration.
// pages/products/+onHydrationEnd.jsimport { reload } from 'vike/client/router'export async function onHydrationEnd() { if (window.location.href.includes('?filter')) await reload()}
If the number of filters isn't infinite, then you can use a paramterized route/products/@filter with onBeforePrerenderStart() in order to pre-render all filters (/products/computer, /products/car, ...).
Upon client-side navigation, the pageContext of the new page is determined dynamically at runtime on the client-side.
Unlike hydration, on client-side navigation, the pageContext is up-to-date, and pageContext.urlParsed.search includes query parameters such as ?filter=computer.