🚀Announcing Flightcontrol - Optimized Deployment for Fullstack Blitz.js and Next.js 🚀
Back to Documentation Menu

Pages

Topics

Jump to a Topic

In Blitz, a page is a React Component exported from a .js, .jsx, .ts, or .tsx file in a pages directory. Each page is associated with a route based on its file path.

All of the following are valid pages:

  • app/pages/about.tsx
  • app/projects/pages/projects/index.tsx
  • app/tasks/pages/projects/[projectId]/tasks/[taskId].tsx

Example: If you create app/pages/about.js that exports a React component like below, it will be accessible at /about.

function About() {
  return <div>About</div>
}

export default About

Pages with Dynamic Routes

Blitz supports pages with dynamic routes. For example, if you create a file called app/pages/posts/[id].js, then it will be accessible at posts/1, posts/2, etc.

To learn more about routing, check the Routing documentation.

Automatic Static Optimization

By default, Blitz pre-renders the static HTML for every page unless you explicitly opt-in to server-side rendering.

For pages with dynamic data, the page's loading fallback state will be rendered unless you prefetch the data to populate the cache.

In some cases, the static optimization can cause an undesirable UX where the first render shows one thing but the second render shows another. For example this happens when using useSession().

Next, we'll introduce some ways to improve the way Blitz pre-renders your pages.

First Render UX

To provide a better User Experience (UX), Blitz tries to automatically pre-render the HTML for your pages, but if your page contains dynamic data fetched with useQuery hooks, Blitz will fallback to the page's loading state and you will not see much benefit from the automatic pre-rendering, because the application will need to immediately make another request to fetch the data it needs to satisfy the query.

In this case you can set Page.suppressFirstRenderFlicker = true, and Blitz will hide the first render's content. This will result in a tiny delay of first paint but will greatly improve the perceived UX.

const Page: BlitzPage = () => {
  return <div>{/* ... */}</div>
}

Page.suppressFirstRenderFlicker = true
export default Page

In case you have set Page.authenticate = true or Page.redirectAuthenticatedTo = true, Blitz will hide the first render's content. For these cases, you can simply ignore setting Page.suppressFirstRenderFlicker = true.

You can also consider prefetching all of the necessary queries that your page needs to complete its first render. You can use either the getStaticProps or getServerSideProps page functions, depending on what you need.

If you create an instance of QueryClient and populate it with query data, then you can pass it as dehydratedState to your page props. Blitz will automatically use the state to build the query cache later when the page tries to render.

import {
  useQuery,
  getQueryKey,
  invokeWithMiddleware,
  dehydrate,
  QueryClient,
  BlitzPage,
  GetServerSidePropsContext,
} from "blitz"
const Page: BlitzPage = () => {
const [organization] = useQuery(getCurrentOrganization, null)
return <div>You have selected: {organization.name}</div> } export async function getServerSideProps(ctx: GetServerSidePropsContext) { const queryClient = new QueryClient()
const queryKey = getQueryKey(getCurrentOrganization, null) await queryClient.prefetchQuery(queryKey, () => invokeWithMiddleware(getCurrentOrganization, null, ctx) )
return { props: { dehydratedState: dehydrate(queryClient), }, } }

In this way, the pre-rendered version of your page HTML will not have to make a request as soon as it loads to fetch any data and will avoid any screen flickering. This is very useful for Search Engine Optimization and the Link Previews used by Social Media sites like Facebook and Twitter.

You can also use prefetching to pre-populate queries that a user might need shortly after the page loads--such a common searches or filter criteria--by setting a staleTime on the query being prefetched.

Persisting Layout Between Page Changes

Blitz has a built-in way to implement cross-page layouts, the Page.getLayout prop. It can be set to a function that receives the page as an argument and returns a JSX element:

import { BlitzPage } from "blitz"
import Layout from "app/core/layouts/Layout"

const Page: BlitzPage = () => {
  return <div>{/* ... */}</div>
}

Page.getLayout = (page) => <Layout title="Title">{page}</Layout>
export default Page

This layout will be rendered over your page. To learn more about layouts, check out the Layout page.

Static Page Generation for Unauthenticated Pages

For pages accessible by anyone without authentication, we recommend using getStaticProps so the page, along with it's data, is 100% statically generated during pre-rendering (like Gatsby). Then the entire static page can be cached on a CDN. This is perfect for public pages like blog posts.

There are two methods for use with static generation, and you'll often use both together.

  1. getStaticProps - To load the data for your page. See the getStaticProps documentation for more details.
  2. getStaticPaths - To load the possible paths for your page. See the getStaticPaths documentation for more details.

Server-side Rendering

Also referred to as "SSR" or "Dynamic Rendering".

If a page uses Server-side Rendering, the page HTML is generated on each request.

To use Server-side Rendering for a page, you need to export an async function called getServerSideProps. This function will be called by the server on every request.

See the getServerSideProps documentation for more details.


Idea for improving this page? Edit it on GitHub.