What is Next.js?
Next JS is a React framework that provides the building blocks to create fast web applications using the React JS JavaScript library. The pre-requisites to building a Next.js application are knowledge of JavaScript and React JS. A beginner is advised to first build an application with JavaScript, then build on that knowledge by re-writing it as a React JS project, then finally a Next.js project.
Why use Next.js?
Previously, I would create all my React JS apps using create-react-app, which provides an out-of-the-box environment to build a React single-page app. However, implementing advanced optimisation features such as SSG (static site generation) and SSR (server-side rendering) requires complicated setup. Next.js provides many useful optimisations out-of-the-box, including SSG, SSR, lazy-loading images and code splitting. Also, the creators of Next.js have created a hosting platform, Vercel, that offers first-class support for Next.js, including automatically providing a CDN (content delivery network) called Vercel Edge Network that serves all pages using static generation and assets (JS, CSS, images, fonts etc.) very quickly.
Next.js provides code splitting automatically, so each page only loads what’s necessary for that page. Therefore, when the homepage is rendered, the code for the rest of the site is not served initially ensuring fast loading times even for websites with hundreds of pages.
In production, Next.js prefetches code for any linked page in the background whenever Link components appear in a browser’s viewport.
Navigation
Routes in Next.js are handled automatically using the file system. You merely have to create pages in the ‘pages’ folder and the routes are created automatically, using the same name as the file. For example, the page at ‘pages/products’ would have route '/products'. You no longer need to manually install the react-router-dom package and define the routes yourself.
To navigate between pages, the Link component is most commonly used. It is also possible to navigate with the router (using the useRouter hook), for example if you want to navigate to a different page after calling a function.
To use the Link component, you must wrap the Link component around an a tag. The Link component must have an href prop, which is passed to the a tag. If you wrap the a tag in another child component, then you must use the passHref prop to ensure it is passed to the a tag via the child component.
Assets
Static assets, like images, are served under the top-level ‘public’ directory. The ‘public’ directory is also useful for robots.txt, Google Site Verification and other static assets.
Next.js provides an Image component that provides automatically Image Optimisation by default. This allows for resizing, optimizing and serving images in modern formats like WebP when it is supported by the browser. It avoids sending large images to devices with a smaller viewport. Images are optimised on-demand as users request them, so build times aren’t increased by shipping a large quantity of images.
Images are lazy loaded by default; therefore, page speed isn’t penalized for images outside the viewport and only load as they are scrolled into viewport. Images are always rendered in a way that avoids Cumulative Layout Shift, which is when the layout shifts after an image has loaded. Cumulative Layout Shift is a Core Web Vital that Googles uses in search ranking.
Metadata
One of the problems with single page applications using client-side rendering, is that we can’t modify the HTML head tag with a different title or metadata based off the specific page that the user has visited. This can negatively affect SEO results as we cannot customize the header to suit individual product pages.
Using Next.js, we can modify the metadata of a page using the Head component provided by Next.
Pre-rendering
One of the major benefits of using Next.js is the ability to easily pre-render page, thus resulting in faster load times for our application which improves both UX and SEO.
Next.js has two forms of pre-rendering: Static Generation and Server-side Rendering.
Static Generation generates HTML at build-time. The pre-rendered HTML is reused on each request.
Server-side Rendering generates the HTML on each request.
Next.js allows you to choose which pre-rendering form to use for each page. You can create a “hybrid” Next.js app by using Static Generation for most pages and using Server-side Rendering for others.
You are recommended to use Static Generation as often as possible because your pages can be built once and served by CDN which is much faster than having a server render the page on each request. Pages you may want to use Static Generation include: marketing pages, blog posts, e-commerce product listings, help and documentation. If the page requires data that is frequently updated or the page content changes on every request, then you cannot use Static Generation and should use Server-side rendering instead.
You could also skip Server-side rendering and just use Client-side rendering instead. You are best suited to using Client-side rendering for pages that do not require SEO, for example you probably don't need a profile page that contains individual user data to be indexed by search engines. In this case, it can be a good idea to pre-render a barebones template of the page and then use client-side JavaScript to fetch the required data and render the rest of the page.
Static Generation
Static Generation can be done both with and without data. To implement with data, you must create an async function called ‘getStaticProps’. ‘getStaticProps’ runs at build time in production and inside the function you can fetch external data and send it as props to the page.
It essentially tells Next.js that the page has data dependencies, so when the page is pre-rendered make sure to resolve them first.
Server-side Rendering
When you need to fetch data at request time, rather than build time, you can use Server-side Rendering. To use Server-side Rendering, you need to export ‘getServerSideProps’ instead of ‘getStaticProps’ from your page.
As it is called at request time, it has a ‘context’ parameter containing request specific parameters.
Server-side rendering should only be used if you need to pre-render a page whose data must be fetched at request time. Time to first byte will be slower than with Static Generation as the server must compute the result on every request, and the request can’t be cached by a CDN without extra configuration.
SWR (stale-while-revalidate)
The team behind Next.js created a React hook for data fetching called SWR. It is highly recommended for fetching data on the client side as it handles caching, revalidation, focus tracking, re-fetching on internal and more. SWR documentation can be found at https://swr.vercel.app/.
SWR is a strategy to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data. With SWR, components get a stream of data updates constantly and automatically. The UI will always be fast and reactive.
Dynamic Routes
To create dynamic routes in Next.js, you add brackets to a page (‘[param]’). For example, the page at ‘pages/product/[id].js’ would match the route at ‘/product/1’. The id will be accessible to the page inside a query object provided by the Next.js router.
To implement dynamic routes, you must define ‘getStaticPaths’. A function that returns a list of paths to use, which must not be an array of strings but rather an array of objects. Each object must have the ‘params’ key and contain an object with the ‘id’ key (as we’re using ‘[id]’ in the file name).
Shallow Routing
Shallow routing allows you to change the URL without running data fetching methods again, that includes ‘getServerSideProps’, ‘getStaticProps’, ‘getInitialProps’.
You will receive the updated ‘pathname’ and ‘query’ via the ‘router’ object without losing state. Shallow routing only works for URL changes in the current page.
API Routes
API Routes let you create an API endpoint inside a Next.js app. You can do so by creating a function inside the ‘pages/api’ directory.
They can be deployed as Serverless Functions (Lambdas).
You should not fetch an API Route from ‘getStaticProps’ or ‘getStaticPaths’. Instead, you should write the server-side code directly in ‘getStaticProps’ or ‘getStaticPaths’ (or call helper function).
Top comments (0)