getInitialProps in Next.js
November 24, 2019
What is Next.js?
Next.js is a react framework which is known to unlock React Server-side rendering by default, creating applications that run both on the client and the server. Applications like that are sometimes referred to as isomorphic or universal Javascript applications. SSR helps to improve the performance of the web application and SEO. Other than that, I also enjoy working with its page-based routing system.
What is getInitialProps?
This method is like another lifecycle added to a React component to do some works before the page component gets rendered. Usually we use it to load data when page loads. This function can run on both server and client side, and it is an async static method which can asynchronously fetch anything that resolves to a javascript plain object, which populates props.
For the initial page load, getInitialProps will execute on the server only. getInitialProps will only be executed on the client when navigating to a different route via the Link component or using the routing APIs. (reference) How to use it?
In _app.js:
static async getInitialProps({ Component, ctx}) {
return {
pageProps: Component.getInitialProps ? await Component.getInitialProps(ctx): {}
};
}
Next.js uses the App component to initialize pages, so it will call getInitialProps from all the page components of the app, otherwise it won’t execute. It lives for the entire lifetime of the client side application. This makes it a great place to keep state when navigating pages. The Component prop is the initial page component and Ctx (context) is the object passed down by getinitalProps(). This function disables the ability to perform automatic static optimization, causing every page in the app to be server-side rendered.
In Document.js:
static async getInitialProps(ctx) {
const originalRenderPage = ctx.renderPage
ctx.renderPage = () =>
originalRenderPage({
// useful for wrapping the whole react tree
enhanceApp: App => App,
// useful for wrapping in a per-page basis
enhanceComponent: Component => Component,
})
// Run the parent `getInitialProps` using `ctx` that now includes our custom `renderPage`
const initialProps = await Document.getInitialProps(ctx)
return initialProps
}
A custom <Document>
is commonly used to augment your application’s <html>
and <body>
tags. It can also include getInitialProps for expressing asynchronous server-rendering data requirements, especially for some CSS-in-JS libraries. ctx object has a renderPage method that synchronously executes the rendering logic. It should be noted that the only reason you should be customizing renderPage is for usage with css-in-js libraries that need to wrap the application to properly work with server-rendering.
In page component:
static async getInitialProps({ req }) {
const res = await fetch('https://api.github.com/repos/zeit/next.js')
const json = await res.json()
return { stars: json.stargazers_count }
}
It is the example code in next document for fetching data when page loads. getInitialProps receives a context object with the following properties:
- pathname — path section of URL
- query — query string section of URL parsed as an object
- asPath — String of the actual path (including the query) shows in the browser
- req — HTTP request object (server only)
- res — HTTP response object (server only)
- err — Error object if any error is encountered during the rendering
When using redux in next.js, _app.js is a good place to provide store for the entire application. I would recommend using next-redux-wrapper to implement it. When fetching data in pages, we can use store to dispatch action in getinitalprops method.
static async getInitialProps({ store, isServer, query }) {
store.dispatch(FetchData()); //FetchData() is an action
return { initialState: store.getState(), isServer};
}
isServer indicates whether it is a server side or client side.