Skip to main content

900. More on Nextjs

Layout

  • define the layout components
    • ex: Header and footer
  • define the styles for the layout components
  • use the components in _app.js
function Header() {
return <h2 className="header">Header - Lorem ipsum dolor.</h2>
}

export default Header;
.footer {
padding: 20px;
text-align: center;
background-color: tomato;
}

.header {
padding: 20px;
text-align: center;
background-color: teal;
}
import '../styles/globals.css'
import Header from "../components/header";
import Footer from "../components/footer";
import '../styles/layout.css';

function MyApp({Component, pageProps}) {
return <>
<Header/>
<Component {...pageProps} />
<Footer/>
</>
}

export default MyApp

Component Level Layouts

  • what if you don't want the Header component to show up in certain pages
  • How to
    • define the desired layout in the specific page
    • update _app.js to consider pages with different layout
import Footer from "../components/footer";

function About() {
return <h2>Lorem ipsum dolor sit amet?</h2>
}

export default About;

About.getLayout = function PageLayout(page) {
return (
<>
{page}
<Footer/>
</>
)
}
import '../styles/globals.css'
import Header from "../components/header";
import Footer from "../components/footer";
import '../styles/layout.css';

function MyApp({Component, pageProps}) {

if (Component.getLayout) {
return Component.getLayout(<Component {...pageProps} />)
}

return <>
<Header/>
<Component {...pageProps} />
<Footer/>
</>
}

export default MyApp

Single Layout

  • we can use a single layout file to define our main website structure
function Layout({children}){
return <>
<Header/>
{children}
<Footer/>
</>

}
export default Layout;
import '../styles/globals.css'
import Footer from "../components/Layout";
import '../styles/layout.css';

function MyApp({Component, pageProps}) {

if (Component.getLayout) {
return Component.getLayout(<Component {...pageProps} />)
}

return <>
<Layout>
<Component {...pageProps} />
<Layout/>
</>
}

export default MyApp

Head Component

  • built-in component for appending elements to the head of the page
import Head from "next/head";

function About() {
return <>
<Head>
<title>Amazon ecommerce</title>
<meta name={'description'} content={'One stop solution to all your needs'}/>
</Head>
<h2>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Corporis, reiciendis?</h2>
</>
}

export default About;
  • you can define a global head section in _app.js
    • child components can override properties defined in parent component i.e _app.js
import '../styles/globals.css'
import Header from "../components/header";
import Footer from "../components/footer";
import '../styles/layout.css';
import Head from "next/head";

function MyApp({Component, pageProps}) {

if (Component.getLayout) {
return Component.getLayout(<Component {...pageProps} />)
}

return <>
<Head>
<title>Amazon gift card</title>
<meta name={'description'} content={'One stop solution to all your needs'}/>
<link rel="icon" href="/favicon.ico" />
</Head>
<Header/>
<Component {...pageProps} />
<Footer/>
</>
}

export default MyApp

Image Component

  • why use image component over native img
    • generate & servers images with the right format, saving considerable size -> space -> loading time
    • serve the images in webp format, which is the preferred format of web
    • lazy loads the image, which increases page load.
      • only load images that are visible in the view-port.
    • adds a placeholder while image is loading
      • this preserves layout, good for clean , non-distributing layout
      • to use place holder you need to use static path
import Image from "next/image";
import image1 from '../public/images/1.jpg';

function Images() {
return (<>

//static image
<Image src={image1} placeholder={"blur"} alt={"static image"} height={400} width={400}/>

//dynamic images
<div style={{display: 'flex'}}>
{
['1', '2', '3', '4'].map(value => {
return <Image key={value} src={'/images/' + value + ".jpg"} alt="my images" height='300'
width='300'/>
})

}
< /div>
</>
)
}

export default Images;
    <Image
src="/example.png"
placeholder="blur"
fill
sizes="(max-width: 768px) 100vw,
(max-width: 1200px) 50vw,
33vw"
/>

Remote Images

  • remote-patterns
  • When using an external URL, you must add it to remotePatterns in next.config.js.
module.exports = {
images: {
domains: ['assets.acme.com'],
},
}

Absolute Imports & Module Paths

  • A better way to organize your imports
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@layout/*": [
"components/layout/*"
]
}
}
}
  • based on this configuration,
    • baseUrl specify all our paths start from the root directory
    • inside path we are aliasing
      • @layout -> components/layout
//before
import '../styles/globals.css'
import Header from "../components/header";
import Footer from "../components/footer";
import '../styles/layout.css';
import Head from "next/head";
//after
import 'styles/globals.css'
import Header from "@layout/header";
import Footer from "@layout/footer";
import 'styles/layout.css';
import Head from "next/head";

Redirects

  • Next.js redirects
  • Redirects allow you to redirect an incoming request path to a different destination path.
  • To use Redirects you can use the redirects key in next.config.js
module.exports = {
reactStrictMode: true,
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
]
},
}
  • Redirects with different matching
    • path matching
    • wildcard path matching
    • regex path matching
    • header, cookie and query matching
    • redirects with base-path support
    • redirects with i18n support

Environment Variables

  • How to define environment variables
    • at project root create a file called .env.local
    • add the environment variables
    • to access the variables use process.env.[variable]
touch .env.local
DB_USER=root
DB_PASSWORD=1234

NEXT_PUBLIC_ANALYTIC_KEY = 13RF2
export async function getServerSideProps(){
const db_user = process.env.DB_USER;
const dv_password = process.env.DB_PASSWORD;
}

export default function HomeComponent(){
console.log(process.env.NEXT_PUBLIC_ANALYTIC_KEY);
return <p>Home component </p>
}
  • by default environment variables are server side only. meaning they won't be available in front-e end
    • but if you want variables to be on front-end as well, prefix the variables with NEXT_PUBLI_[variable_name]
    • but be careful though not to include secret variables in the font-end end: i.e db_password, token_key

Prefetching

  • Prefetch pages for faster client-side transitions. This method is only useful for navigations without next/link, as next/link takes care of prefetching pages automatically.
  • Let's say you have a login page, and after a login, you redirect the user to the dashboard. For that case, we can prefetch the dashboard to make a faster transition, like in the following example:
import { useCallback, useEffect } from 'react'
import { useRouter } from 'next/router'

export default function Login() {
const router = useRouter()
const handleSubmit = useCallback((e) => {
e.preventDefault()

//const result = post("/login").data(data)
//id result ok... move user to next destination
router.push('/dashboard')
}, [])

useEffect(() => {
// Prefetch the dashboard page
router.prefetch('/dashboard')
}, [])

return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit">Login</button>
</form>
)
}

Important Next.js Typescript Snippets

Rendering

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'

export const getStaticProps: GetStaticProps = async (context) => {
// ...
}

export const getStaticPaths: GetStaticPaths = async () => {
// ...
}

export const getServerSideProps: GetServerSideProps = async (context) => {
// ...
}

API Request and Response

import type { NextApiRequest, NextApiResponse } from 'next'

type Data = {
name: string
}

export default (req: NextApiRequest, res: NextApiResponse<Data>) => {
res.status(200).json({ name: 'John Doe' })
}

config.json

// @ts-check

/**
* @type {import('next').NextConfig}
**/
const nextConfig = {
/* config options here */
}

module.exports = nextConfig