/nextjs-tut

walk through nextjs tutorial

Primary LanguageJavaScript

NextJS Official Tutorial

This is a starter template for Learn Next.js.

C1 - Create a Next.js App - Setup

Chapter Link: https://nextjs.org/learn/basics/create-nextjs-app

nvm use 18

npx create-next-app@latest nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"

C2 - Navigate Between Pages

Chapter Link: https://nextjs.org/learn/basics/navigate-between-pages

Creating New Pages

  • depends on file system
  • root of pages in ./pages folder of project
  • folders and file name represent the routing

Navigation

  • Link component of next/link to navigate
    • acts like a element, but route needs to be set manually
    • difference being that it's fully client side (i.e. not fetching from server)
    • see pageurl in wagtail templates
    • or url in django templates

Refs:

C3 - Assets, Metadata, and CSS

Chapter Link: https://nextjs.org/learn/basics/assets-metadata-css

Assets

  • public folder for assets
  • sample route would be /images/profile.jpg for public/images/profile.jpg
  • for images, leverage Image component of next/image
    • handles optimization (e.g. size, format)

Refs.:

Metadata

  • Head component available from next/head e.g. to modify page title

Refs.:

Third Party JS

  • risk of render blocking avoided with Script component of next/script
  • strategy to define how important the script is:
    • beforeInteractive
    • afterInteractive
    • lazyOnload
  • onLoad prop to execute extra JS after loading

Refs.:

Styling

component level styling

  • with extra file matching component name
  • components/Button.module.css
  • components/Button.js
  • import styles from './Button.module.css' within components/Button.js
  • Regular stylesheets and global CSS files are still supported

External Stylesheets

  • in case of installation via node
  • e.g. global import: import 'bootstrap/dist/css/bootstrap.css' within pages/_app.js
  • e.g. component level: import '@reach/dialog/styles.css'

Refs:

Layout Component

Motivation: example for component-level styles and creating a container component

  • layout component to carry styling to serve as container for children components
  • components/layout.js
  • components/layout.module.css
  • connect CSS via import styles from './layout.module.css'; in JS file
  • and mount to JSX HTML element via className={styles.container}
  • container being defined in the CSS file
  • next creates unique class names on app level

Global Styles

  • global styles can only be imported in _app.js

Polishing up the Layout

Motivation: Remove more of the boilerplate example code

  • usage of constant to render sth
  • meta tags inside of <Header> layout which will be included in children (if used in/as children)
  • ternary JSX fragment pattern depending on home flag

Styling Tips

  1. clsx to toggle classes https://www.npmjs.com/package/clsx
.success {
  color: green;
}
.error {
  color: red;
}
import styles from './alert.module.css';
import { clsx } from 'clsx';

export default function Alert({ children, type }) {
  return (
    <div
      className={clsx({
        [styles.success]: type === 'success',
        [styles.error]: type === 'error',
      })}
    >
      {children}
    </div>
  );
}
  1. Customizing PostCSS Config and 3. tailwind
  • manipulation of the CSS shipped to the client such that
  • vendor prefixes are set (distinguish whose CSS it actually is)
  • collisions are voided
npm install -D tailwindcss autoprefixer postcss

-D for --save-dev (separate from prod package)

  1. SASS
npm install -D sass

Ref.:

C4 - Pre-rendering and Data Fetching

Lesson goals:

pre-rendering overview

a) static rendering

Complete static HTML can be hosted by e.g. nginx

typical: Marketing pages

b) server side rendering

creates the HTML for each request

  • run some of the js in the background and return some of the app as html
  • each way, saves time on client side to render vs pure react app
  • use static if not much dynamic elements are present (i.e. data is updated)
  • static/server side can be configured on page level

static

  • example to get data from the filesystem and include it into our component
export async function getStaticProps() {
    const allPostsData = getSortedPostsData(); // external calls 
    return {
        props: {
            allPostsData,
        },
    };
}
  • Within the component module, above the functional component:
  • convention name getStaticProps
  • returns {props: { <prop name>: <prop value>}} or short {props: {variableName}} (Object Property Shorthand)
  • runs only on the server side (that's why we were able to use nodes API)
  • runs on every request in dev mode
  • runs once at build time
  • can only be exported from a page

We could just as well do an external API call instead of reading files from the local file system

export async function getSortedPostsData() {
  // Instead of the file system,
  // fetch post data from an external API endpoint
  const res = await fetch('..');
  return res.json();
}

or DB calls

import someDatabaseSDK from 'someDatabaseSDK'

const databaseClient = someDatabaseSDK.createClient(...)

export async function getSortedPostsData() {
  // Instead of the file system,
  // fetch post data from a database
  return databaseClient.query('SELECT posts...')
}

Ref.:

Fetching Data at Request Time

  • to fetch non-static data

You should use getServerSideProps only if you need to pre-render a page whose data must be fetched at request time.

export async function getServerSideProps(context) {
    // magic
  return {
    props: {
      // props for your component
    },
  };
}

Ref.:

Client-side Rendering

Node specific details:

  • fs is a Node.js module that let's you read files from the file system.
  • path is a Node.js module that let's you manipulate file paths.
  • matter is a library that let's you parse the metadata in each markdown file.

C5 - Dynamic Routes

Chapter Link: https://nextjs.org/learn/basics/dynamic-routes

  • dynamic paths need a [id].js within a subfolder
  • it contains
    • the React component on how to render the data
    • getStaticPaths to tell next.js what paths do exists
    • and getStaticProps to tell next.js what to render on each dynamic route

getStaticPaths

  • runs with every request in dev
  • runs once at build time in prod
  • expects paths to be of [{params: {id: 'theActualId'},...] format
export async function getStaticPaths() {
  const paths = getAllPostIds();
  return {
    paths,
    fallback: false,
  };
}

Ref.:

get static props

export async function getStaticProps({params}) {
    const postData = await getPostData(params.id);
    return {
        props: {
            postData,
        }
    };
}

In case of external data

  • ... the utility function could do a DB query or an API query:
export async function getAllPostIds() {
  // Instead of the file system,
  // fetch post data from an external API endpoint
  const res = await fetch('..');
  const posts = await res.json();
  return posts.map((post) => {
    return {
      params: {
        id: post.id,
      },
    };
  });
}

Dynamic Page Layout

  • in the case of markdown, dangerouslySetInnerHTML can be used
  • in combo with remark library
  • and remark-html
  • additionally date-fns was introduced for date formatting

Index Route

  • since we already have posts metadata (including the ide)
  • <Link href={/posts/${id}}>{title}</Link>

Error Pages

  • custom 404 page can be created within pages: pages/404
  • same for 500

Ref.:

C6 - API Routes

Chapter link: https://nextjs.org/learn/basics/api-routes

  • offers independent API routes
  • can be dynamic as well just like pages
  • use cases
    • can be used to save form input directly to the database
    • preview route
  • not to be used within getStaticProps, getStaticPaths since we can avoid the HTTP traffic altogether with a utility function (i.e. which could be called by both getStatic* and the API route handler)
// pages/api/hello.js
// accessable at http://localhost:3000/api/hello
export default function handler(req, res) {
  res.status(200).json({ text: 'Hello' });
}

C7 - Deployment

Chapter Link: https://nextjs.org/learn/basics/deploying-nextjs-app/

workflow for Vercel

Vercel advantages: