At the Nextjs 2022 Conference, the team announced Nextjs v13 with some amazing features such as improved next/image
, React Server Components, Turbopack (Webpack successor), improvement to the Middleware API, and a new app
directory. The stable version of Nextjs 13 has most of these features while other features available such as app directory, and Turbopack are currently in beta.
One of the biggest concerns developers have, when new version updates are released, is what the breaking changes are and how they would impact their current development setup. In Nextjs v13, the breaking changes that could disrupt developer environments are:
- The minimum React version has been bumped from 17.0.2 to 18.2.0.
- The minimum Node.js version has been bumped from 12.22.0 to 14.6.0 since 12.x has reached end-of-life (PR).
These changes can currently be deployed to AWS Amplify Hosting and you will learn the steps to do so in this article. I should mention that all of Next.js features are supported including server side rendering.
Start with a Next.js App
Let’s get started by bootstrapping a nextjs project. Run this command on your terminal:
yarn create next-app
When this is done, open the project in your code editor.
cd project-name
code . (for vs code users)
Server Side Rendering
Use getServerSideProps
when you need to render a page whose data must be fetched at request time. For server-side rendered apps that need to render the page with user data directly on the server.
Let’s fetch user data from an external API and render this page with the data.
const getServersideprops = ({ data }) => {
return (
<div className="my-12">
<h2 className='text-4xl font-extrabold dark:text-gray-900'>Load page with Server side data </h2>
{data.map(dt => (
<div className="border-2 shadow-sm border-gray-200 rounded p-3 space-y-2 my-4">
<h3 className='my-4 text-2xl text-gray-800'> {dt.name.firstname} {dt.name.lastname}</h3>
<p className='my-4 text-lg text-gray-800 font-bold'> {dt.email}</p>
<p className='my-4 text-lg text-gray-500 uppercase'> {dt.address.city}</p>
<p className='my-4 text-lg text-gray-800'> {dt.phone}</p>
</div>
))}
</div>
)
}
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch('https://fakestoreapi.com/users')
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default getServersideprops
Pass the data you want to render as props to the component. Run your server with yarn dev
. You should get something like this.
Static Site Generation
Use getStaticPaths()
when you’re using dynamic routes with getStaticProps
and need to define a list of paths to be statically generated. This comes in handy when working with a content management system (CMS) or statically pre-rendering pages with data from a database.
getStaticProps
statically render a page at build time and passes the data to the component using props.
Let’s render a list of products from our fake API on a page. Update your pages/product/index.js
with this:
import Link from "next/link"
const getStaticprops = ({ product }) => {
return (
<div className="my-12">
{product.map(pr => (
<div className="border-2 shadow-sm border-gray-200 rounded p-3 space-y-4 my-4" key={pr.id}>
<p> Title: {pr.title}</p>
<p> Description: {pr.description}</p>
<p> ${pr.price}</p>
<Link href={`products/${pr.id}`} className='font-medium text-blue-600 dark:text-blue-500 hover:underline'>
<p> Get here</p>
</Link>
</div>
))
}
</div>
)
}
export async function getStaticProps() {
// Run API calls in parallel
const productsResponse = await fetch('https://fakestoreapi.com/products')
const products = await productsResponse.json()
return {
props: {
product: products
},
}
}
export default getStaticprops
When you run your server, you will see this:
We need to pre-render a page with data from each of those products by generating paths using getStaticPath()
.
First, let’s fetch single product data from API using the productId
and then pass the data as props to the Component using getStaticProps
.
export async function getStaticProps(context) {
const { params } = context
// Call an external API endpoint to get posts
const response = await fetch(`https://fakestoreapi.com/products/${params.productId}`)
const data = await response.json()
return {
props: {
product: data
}
}
}
Then we use getStaticPaths
to fetch all the product data and assign the id of each product to params.productId
.
export async function getStaticPaths() {
const response = await fetch('https://fakestoreapi.com/products')
const data = await response.json()
const paths = data.map(product => {
return {
params: {
productId: `${product.id}`
}
}
})
return {
paths,
fallback: true
}
}
When you run this, you should be able to view data of a single product item pre-rendered on a page with its dynamically generated path.
Image Optimization
There are improvements to the Nextjs image in this Nextjs v13. Most importantly, these two new improvements:
- Easier to style and configure
- More accessible requiring
alt
tags by default
<Image
alt="layout Responsive"
src={pr.image}
width={700}
placeholder="blur"
blurDataURL={blurDataURL}
height={475}
sizes="(max-width: 768px) 100vw,(max-width: 1200px) 50vw, 33vw"
style={{
width: '100%',
height: 'auto',
}}
/>
Here, we have an optimized image with a blur placeholder. It’s also responsive on all screen sizes.
Middleware
Nextjs introduced middlewares in Nextjs v12 so developers can run code before a request is completed and manipulate the incoming request. This is important when running A/B tests, setting authentication guards, or setting request headers. In Nextjs v13, you can now respond to a middleware using NextResponse
and set request headers.
Let’s create a middleware to redirect users to /products
when they go to the /redirect
path.
//middleware.js
import { NextResponse } from 'next/server'
export function middleware(request) {
if (request.nextUrl.pathname.startsWith('/redirect')) {
return NextResponse.redirect(new URL('/products', request.url))
}
}
API Routing
API Routes enable developers to build GraphQL or REST APIs. All files inside pages/api
is mapped to /api/*
and will be treated as an API endpoint instead of a page
.
Let’s update pages/api/hello.js
with this
export default function handler(req, res) {
res.status(200).json({ name: 'Christain Nwamba' })
}
You can consume the endpoint on a page
like this:
const ApiRouting = () => {
const [hello, setHello] = useState('')
const fetchName = async () => {
if (global.window) {
const response = await fetch("/api/hello")
const data = await response.json()
setHello(data)
}
}
fetchName()
return (
<div>
<h2 className='text-4xl font-extrabold dark:text-gray-900'> Using API Routes </h2>
<h3 className='text-3xl font-extrabold dark:text-gray-700'> Hey {hello.name} </h3>
</div>
)
}
Deploy to Amplify Hosting
Amplify Hosting supports all Next.js features, including the new Next.js 13 features. Let’s walk through the steps to deploy your app.
Ensure you’ve created and pushed your code to GitHub or your preferred Git provider.
Head to AWS Amplify Hosting and click on the Host your web app button. You’ll be redirected to this page.
Select your Git provider (Github, in my case) and click on the Connect branch button. Ensure you install and authorize AWS Amplify to access your repositories.
Click the Next button.
You’ll be redirected to this page to configure build settings.
Click on Next. Review the settings and click on the Save and deploy button.
The deployment will take a few minutes and when it’s done, click on the deployed app link and check if all the features are working correctly.