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
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.
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.
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.
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.
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.
getStaticProps
- To load the data for your page. See the
getStaticProps
documentation for more details.getStaticPaths
- To load the possible paths for your page. See
the getStaticPaths
documentation for more
details.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.