天天看點

一篇文章掌握Next.js的核心要點

Next.js整體介紹

Next.js是React服務端渲染應用架構,用于建構SEO友好的SPA應用。
  1. 支援兩種渲染方式,靜态生成和伺服器端渲染。
  2. 基于頁面的路由系統,路由零配置。
  3. 自動代碼拆分,優化頁面加載速度。
  4. 支援靜态導出,可将應用導出為靜态網站。
  5. 内置CSS-in-JS庫styled-jsx
  6. 方案成熟,可用于生産環境,世界許多公司都在使用。
  7. 應用部署簡單,擁有專屬部署環境vercel,也可以部署在其他環境。

建立Next.js項目

  • 建立
npm init next-app mynext           
  • 運作
npm run dev           
  • 通路
localhost:3000           
出現下面的頁面表示項目初始化成功。
一篇文章掌握Next.js的核心要點

基于頁面的路由系統

建立頁面

  • 在Next.js中,頁面是被放置在pages檔案夾中的React元件。
  • 元件需要被預設導出
  • 元件檔案中不需要引入react
  • 頁面位址與檔案位址是對應的關系
建立一個list頁面
  1. 在pages檔案夾下建立一個list.js
export default function List() {
    return (
        <div>
            <h1>Hello,Next!</h1>
        </div>
    )
}           
  1. 在路由下通路下面的位址即可
http://localhost:3000/list           

頁面跳轉

注意事項
  • Link元件預設使用JavaScript進行頁面跳轉,即SPA形式的跳轉。
  • 如果浏覽器中JavaScript被禁用,則使用連結跳轉
  • Link元件中不應添加除href屬性以外的屬性,其餘屬性添加到a标簽上
  • Link元件通過預取功能自動優化應用程式以獲得最佳性能。
從首頁跳轉到list頁面的代碼(預設去pages檔案夾下找list)
import Link from 'next/link'
export default function Home() {
    return (
        <div >
            <Link href="/list"><a>List Page</a></Link>
        </div>
    )
}           

Next.js應用中的靜态通路

應用程式根目錄中的public檔案夾用于提供靜态資源,可以通過以下形式進行通路:(下面的/就代表了public這個檔案夾)
一篇文章掌握Next.js的核心要點
下面的代碼将通路public檔案夾下的CSS.png這個圖檔
<img src="/images/CSS.png" alt="" />           

修改頁面中的中繼資料

通過Head元件修改中繼資料。Head元件的主要作用是将html的标簽添加到頁面的head中。
  • Home.js
import Link from 'next/link'
import Head from 'next/head'
export default function Home() {
    return (
        <div >
            <Head>
                <title>My Next</title>
            </Head>
            <Link href="/list"><a>List Page</a></Link>
            <img src="/images/CSS.png" alt="" />
        </div>
    )
}           
  • list.js
import Head from 'next/head'
export default function List() {
    return (
        <div>
            <Head>
                <title>List Page</title>
            </Head>
            <h1>Hello,Next!</h1>
        </div>
    )
}           

添加樣式的方式

styled-jsx

在next中内置了styled-jsx,它是一個CSS-in-JS庫,允許在React元件中編寫CSS,CSS僅作用于元件内部。
  • 修改跳轉到list頁面的連結樣式
import Link from 'next/link'
import Head from 'next/head'
export default function Home() {
    return (
        <div >
            <Head>
                <title>My Next</title>
            </Head>
            <Link href="/list"><a className="demo" >List Page</a></Link>
            <style jsx>
                {`
                    .demo {
                        color: red;
                    }
                `}
            </style>
        </div>
    )
}           

CSS樣式

CSS子產品

通過使用CSS子產品功能,允許将元件的CSS樣式編寫在單獨的CSS檔案中,CSS子產品約定樣式檔案的名稱必須

元件檔案名稱.module.css

# list.js
import Head from 'next/head'
import styles from './list.module.css';
export default function List() {
    return (
        <div>
            <Head>
                <title>List Page</title>
            </Head>
            <h1 className={styles.demo}>Hello,Next!</h1>
        </div>
    )
}

# list.module.css
.demo {
    color: blueviolet;
}           

添加全局樣式

  1. 在pages檔案夾下建立_app.js檔案并加入如下代碼。
  2. 在項目根目錄下建立styles檔案夾,并在其中建立global.css
  3. 在_app.js中通過import引入global.css
  4. 重新啟動開發伺服器
注意:在_app.js中需要加入下面的固定代碼
export default function App({ Component, pageProps }) {
    return <Component {...pageProps} />
}           

預渲染

什麼是預渲染?
  • 預渲染是指資料和HTML的拼接在伺服器端提前完成
  • 預渲染可以使SEO更加友好
  • 預渲染會帶來更好的使用者體驗,可以無需運作JS即可檢視應用程式UI
預渲染的兩種形式
  • 在Next.js中支援兩種形式的預渲染:靜态生成和伺服器端渲染。
  • 靜态生成和伺服器端渲染是生成HTML樹的時機不同。
  • 靜态生成:靜态生成是在建構時生成HTML,以後的每個請求都共用建構時生成好的HTML。
  • 伺服器端渲染:伺服器端渲染是在請求時生成HTML,每個請求都會重新生成HTML。
兩種預渲染方式的選擇
  • Next.js允許開發者為每個頁面選擇不同的預渲染方式,不同的預渲染方式擁有不同的特點,應根據場景進行渲染。
  • 大多數頁面建議靜态生成。
  • 靜态生成一次建構,反複使用,通路速度快,因為頁面都是事先生成好的。适用場景:營銷頁面、部落格文章、電子商務産品清單、幫助和文檔。
  • 伺服器端渲染通路速度不如靜态生成,但是由于每次請求都會重新渲染,适用于資料頻繁更新的頁面或頁面内容随請求變化而變化的頁面。

實作靜态生成

無資料和有資料的靜态生成。
  • 如果元件不需要再其他地方擷取資料,直接進行靜态生成。
  • 如果元件需要在其他地方擷取資料,在建構時next.js會預先擷取元件需要的資料,然後再對元件進行靜态生成。

無資料的靜态生成

  1. 先把.next檔案夾删掉
  2. 運作build指令
npm run build           

有資料的靜态生成

通過getStaticProps方法擷取元件靜态生成時需要的資料,并通過props的方式将資料傳遞給元件,該方法是一個異步函數,需要在元件内部進行導出,在開發模式下,getStaticProps改為在每個請求上運作。
import Head from 'next/head'
import styles from './list.module.css';
import { readFile } from 'fs';
import { promisify } from 'util';
import { join } from 'path'

const read = promisify(readFile);
export default function List({data}) {
    return (
        <div>
            <Head>
                <title>List Page</title>
            </Head>
            <h1 className={styles.demo}>Hello,Next!</h1>
            <h2>控制台列印的是{data}</h2>
        </div>
    )
}

export async function getStaticProps () {
    let data = await read(join(process.cwd(),'pages','_app.js'),'utf-8');
    console.log(data)
    return {
        props: {
            data
        }
    }
}           

npm start和npm run dev的差別

  • start啟動的是生産環境中的代碼
  • dev啟動的是開發環境中的代碼

實作基于動态路由的靜态生成

基于參數為頁面元件生成HTML頁面,有多少參數就生産多少HTML頁面,在建構應用時,先擷取使用者可以通路的所有路由參數,再根據路由參數擷取具體的資料,然後根據資料生成靜态HTML。
  1. 建立基于動态路由的頁面元件檔案,命名時在檔案名稱外面加上[],比如[id].js
一篇文章掌握Next.js的核心要點
  1. 導出異步函數getStaticPaths,用于擷取所有使用者可以通路的路由參數。
  2. 導出異步函數getStaticProps,使用者根據路由參數擷取具體的資料。

注意:getStaticProps和getStaticPaths隻運作在伺服器端,永遠不會運作在用戶端,甚至不會被打包到用戶端JavaScript中,意味着這裡可以随意些服務端代碼,比如查詢資料庫。

[id].js

export default function Post({data}) {
    return (
        <div>
            <span>{data.id}</span>
            <span>{data.title}</span>
        </div>
    )
}

// 傳回使用者能夠通路到的所有的路由參數
export async function getStaticPaths() {
    return {
        paths: [{params: {id: '1'}},{params: {id: '2'}}],
        fallback: false
    }
}

// 傳回路由參數對應的具體資料
export async function getStaticProps({params}) {
    const id = params.id;
    let data;
    switch (id) {
        case '1':
            data = {id: "1",title: 'Hello'};
            break;
        case '2':
            data = {id: "2", title: 'World'};
            break;
        default:
            data = {};
    }
    return {
        props: {
            data
        }
    }
}           

fallback選項的作用

fallback設定為false表示如果使用者請求的參數,不在指定參數範圍内,則傳回404頁面,如果這個值是true,表示擷取使用者請求的資料并生成對應的靜态頁面。

下面是fallback為true時[id].js的代碼

import { useRouter } from 'next/router'
export default function Post({data}) {
    const router = useRouter();
    if (router.isFallback) return <div style={{color: 'red'}}>Loading...</div>
    return (
        <div>
            <span>{data.id}</span>
            <span>{data.title}</span>
        </div>
    )
}

// 傳回使用者能夠通路到的所有的路由參數
export async function getStaticPaths() {
    return {
        paths: [{params: {id: '1'}},{params: {id: '2'}}],
        fallback: true
    }
}

// 傳回路由參數對應的具體資料
export async function getStaticProps({params}) {
    const id = params.id;
    let data;
    switch (id) {
        case '1':
            data = {id: "1",title: 'Hello'};
            break;
        case '2':
            data = {id: "2", title: 'World'};
            break;
        case '3':
            data = {id: '3',title: 'Hello World'};
            break;
        default:
            data = {};
    }
    return {
        props: {
            data
        }
    }
}           

自定義404頁面

要建立自定義404頁面,需要在pages檔案夾中建立404.js檔案。
export default function Custom404() {
    return (
        <h1>404 Not Found</h1>
    )
}           

API Routers

API Routers可以了解為接口,用戶端向服務端發送請求擷取資料的接口,Next.js應用允許React開發者編寫伺服器端代碼建立資料接口。

實作API Routers

  1. 在pages/api檔案夾中建立API Routes檔案,比如user.js
  2. 在檔案中預設導出請求處理函數,函數有兩個參數,req為請求對象,res為響應對象。
  3. 通路API Routes: localhost:3000/api/user

注意:不要在getStaticProps或getStaticPaths函數中通路API Routers,因為這兩個函數就是在伺服器端運作的,可以直接寫伺服器端代碼。

下面是/pages/api/user.js

export default (req, res) => {
    res.send({ name: 'hello' })
}