国产成人精品999视频&日本一区二区亚洲人妻精品&久久久精品国产99久久精&99热这里只有成人精品国产&精品国产剧情av一区二区&成人亚洲精品久久久久app&国产精品美女高潮抽搐A片

Next.js 備忘清單

NPM version Downloads Repo Dependents Github repo

這是一份快速參考備忘單,包含 Next.js 的 API 參考列表和一些示例

入門

創(chuàng)建項目

npx create-next-app@latest
# or
yarn create next-app
# or
pnpm create next-app

或者創(chuàng)建 TypeScript 項目

npx create-next-app@latest --typescript
# or
yarn create next-app --typescript
# or
pnpm create next-app --typescript

運行 npm run devyarn devpnpm dev 以在 http://localhost:3000 上啟動開發(fā)服務器

添加首頁

使用以下內容填充 pages/index.js

function HomePage() {
  return <div>Welcome to Next.js!</div>
}

export default HomePage

Next.js 是圍繞頁面的概念構建的。 頁面是從 pages 目錄中的 .js、.jsx、.ts.tsx 文件導出的 React 組件

getServerSideProps

function Page({ data }) {
  // 渲染數(shù)據(jù)...
}

// 每個請求都會調用它
export async function getServerSideProps() {
  // 從外部 API 獲取數(shù)據(jù)
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  // 通過 props 向頁面?zhèn)鬟f數(shù)據(jù)
  return { props: { data } }
}

export default Page

如果您從頁面導出一個名為 getServerSideProps(服務器端渲染)的函數(shù),Next.js 將使用 getServerSideProps 返回的數(shù)據(jù)在每個請求上預渲染該頁面

  • 當您直接請求此頁面時,getServerSideProps 在請求時運行,此頁面將使用返回的 props 進行預渲染
  • 當您通過 next/linknext/router 在客戶端頁面轉換上請求此頁面時,Next.js 會向服務器發(fā)送 API 請求,服務器運行 getServerSideProps

getStaticPaths

// pages/posts/[id].js
export async function getStaticPaths() {
  // 當這是真的時(在預覽環(huán)境中)不要預呈現(xiàn)任何靜態(tài)頁面(更快的構建,但更慢的初始頁面加載)
  if (process.env.SKIP_BUILD_STATIC_GENERATION) {
    return {
      paths: [],
      fallback: 'blocking',
    }
  }

  // 調用外部 API 端點以獲取帖子
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 根據(jù)帖子獲取我們要預渲染的路徑 在生產(chǎn)環(huán)境中,預渲染所有頁面
  // (構建速度較慢,但初始頁面加載速度較快)
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // { fallback: false } 表示其他路由應該 404
  return { paths, fallback: false }
}

如果頁面具有動態(tài)路由并使用 getStaticProps,則需要定義要靜態(tài)生成的路徑列表

  • 數(shù)據(jù)來自無頭 CMS
  • 數(shù)據(jù)來自數(shù)據(jù)庫
  • 數(shù)據(jù)來自文件系統(tǒng)
  • 數(shù)據(jù)可以公開緩存(非用戶特定)
  • 頁面必須預渲染(用于 SEO)并且速度非常快 —— getStaticProps 生成 HTML 和 JSON 文件,這兩種文件都可以由 CDN 緩存以提高性能

getStaticProps

// 帖子將在構建時由 getStaticProps() 填充
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// 這個函數(shù)在服務器端的構建時被調用。
// 它不會在客戶端調用,因此您甚至可以直接進行數(shù)據(jù)庫查詢。
export async function getStaticProps() {
  // 調用外部 API 端點以獲取帖子。 您可以使用任何數(shù)據(jù)獲取庫
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 通過返回 { props: { posts } },Blog 組件將在構建時接收 `posts` 作為 prop
  return {
    props: {
      posts,
    },
  }
}

export default Blog

在服務器端的構建時被調用

增量靜態(tài)再生

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// 這個函數(shù)在服務器端的構建時被調用
// 如果啟用了重新驗證并且有新請求進入,它可能會在無服務器功能上再次調用
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js 將嘗試重新生成頁面:
    // - 當請求進來時
    // - 最多每 10 秒一次
    revalidate: 10, // 片刻之間
  }
}

// 這個函數(shù)在服務器端的構建時被調用
// 如果尚未生成路徑,則可能會在無服務器函數(shù)上再次調用它
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 根據(jù)帖子獲取我們要預渲染的路徑
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // 我們將在構建時僅預渲染這些路徑
  // { fallback: blocking } 如果路徑不存在,服務器將按需呈現(xiàn)頁面
  return { paths, fallback: 'blocking' }
}

export default Blog
  • 在初始請求之后和 10 秒之前對頁面的任何請求也會被緩存和即時
  • 在 10 秒窗口之后,下一個請求仍將顯示緩存的(陳舊的)頁面
  • Next.js 在后臺觸發(fā)頁面的重新生成
  • 一旦頁面生成成功,Next.js 將使緩存失效并顯示更新后的頁面。如果后臺重新生成失敗,舊頁面仍將保持不變

使用 useEffect 客戶端數(shù)據(jù)獲取

import { useState, useEffect } from 'react'

function Profile() {
  const [data, setData] = useState(null)
  const [isLoading, setLoading] = useState(false)

  useEffect(() => {
    setLoading(true)
    fetch('/api/profile-data')
      .then((res) => res.json())
      .then((data) => {
        setData(data)
        setLoading(false)
      })
  }, [])

  if (isLoading) return <p>Loading...</p>
  if (!data) return <p>No profile data</p>

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
    </div>
  )
}

使用 SWR 獲取客戶端數(shù)據(jù)

import useSWR from 'swr'

const fetcher = (...args) => fetch(...args).then((res) => res.json())

function Profile() {
  const { data, error } = useSWR('/api/profile-data', fetcher)

  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
    </div>
  )
}

靜態(tài)文件服務

Next.js 可以在根目錄中名為 public 的文件夾下提供靜態(tài)文件,如圖像。 然后,您的代碼可以從基本 URL (/) 開始引用 public 中的文件

import Image from 'next/image'

function Avatar() {
  return (
    <Image
      src="/me.png"
      alt="me"
      width="64"
      height="64"
    />
  )
}

export default Avatar

支持的瀏覽器和功能

Next.js 支持零配置的現(xiàn)代瀏覽器

  • Chrome 64+
  • Edge 79+
  • Firefox 67+
  • Opera 51+
  • Safari 12+

Next.js 支持在 package.json 文件中配置 Browserslist

{
  "browserslist": [
    "chrome 64",
    "edge 79",
    "firefox 67",
    "opera 51",
    "safari 12"
  ]
}

內置 CSS 支持

添加全局樣式表

如果不存在,請創(chuàng)建一個 pages/_app.js 文件。 然后,導入 styles.css 文件

import '../styles.css';

// 在新的“pages/_app.js”文件中需要此默認導出
export default function MyApp({
  Component, pageProps
}) {
  return <Component {...pageProps} />
}

例如,考慮以下名為 styles.css 的樣式表

body {
  font-family:
    'SF Pro Text', 'SF Pro Icons',
    'Helvetica Neue', 'Helvetica',
    'Arial', sans-serif;
  margin: 0 auto;
}

從 node_modules 導入樣式

對于全局樣式表,如 bootstrapnprogress,您應該在 pages/_app.js 中導入文件

// pages/_app.js
import 'bootstrap/dist/css/bootstrap.css'

export default function MyApp({
  Component, pageProps
}) {
  return <Component {...pageProps} />
}

Next.js 9.5.4 開始,您的應用程序中的任何地方都允許從 node_modules 導入 CSS 文件

添加組件級 CSS (CSS Modules)

您無需擔心 .error {} 與任何其他 .css.module.css 文件!他將被生成 hash 名稱

.error {
  color: white;
  background-color: red;
}

然后,創(chuàng)建 components/Button.js,導入并使用上面的 CSS 文件:

import styles from './Button.module.css'

export function Button() {
  return (
    <button
      type="button"
      // 請注意“error”類
      // 是如何作為導入的“styles”對象的屬性訪問的
      className={styles.error}
    >
      Destroy
    </button>
  )
}

Sass 支持

Next.js 允許您使用 .scss.sass 擴展名導入 Sass,可以通過 CSS 模塊和 .module.scss.module.sass 擴展名使用組件級 Sass

$ npm install --save-dev sass

在使用 Next.js 的內置 Sass 支持之前,請務必安裝 sass

自定義 Sass 選項

通過在 next.config.js 中使用 sassOptions 來實現(xiàn)配置 Sass 編譯器。例如添加 includePaths

const path = require('path')

module.exports = {
  sassOptions: {
    includePaths:
        [path.join(__dirname, 'styles')],
  },
}

Sass 變量

/* variables.module.scss */
$primary-color: #64ff00;

:export {
  primaryColor: $primary-color;
}

pages/_app.js 中導入 variables.module.scss

import variables from '../styles/variables.module.scss'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout color={variables.primaryColor}>
      <Component {...pageProps} />
    </Layout>
  )
}

CSS-in-JS

最簡單的一種是內聯(lián)樣式:

function HiThere() {
  return (
    <p style={{ color: 'red' }}>hi 這里</p>
  )
}

export default HiThere

使用 styled-jsx 的組件如下所示:

function HelloWorld() {
  return (
    <div>
      Hello world
      <p>scoped!</p>
      <style jsx>{`
        p { color: blue; }
        div { background: red; }
        @media (max-width: 600px) {
          div { background: blue; }
        }
      `}</style>
      <style global jsx>{`
        body { background: black; }
      `}</style>
    </div>
  )
}

export default HelloWorld

當然,你也可以使用 styled-components

Layouts

基礎示例

// components/layout.js
import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  return (
    <>
      <Navbar />
      <main>{children}</main>
      <Footer />
    </>
  )
}

帶有自定義應用程序的單一共享布局

// pages/_app.js
import Layout from '../components/layout'

export default function MyApp({ Component, pageProps }) {
  return (
    <Layout>
      <Component {...pageProps} />
    </Layout>
  )
}

使用 TypeScript

// pages/index.tsx
import type { ReactElement } from 'react'
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'

const Page: NextPageWithLayout = () => {
  return <p>hello world</p>
}

Page.getLayout = function getLayout(page: ReactElement) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}

export default Page
// pages/_app.tsx

import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
  getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
  Component: NextPageWithLayout
}

export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
  // 使用在頁面級別定義的布局(如果可用)
  const getLayout = Component.getLayout ?? ((page) => page)

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

每頁布局

// pages/index.js
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'

export default function Page() {
  return (
    /** Your content */
  )
}

Page.getLayout = function getLayout(page) {
  return (
    <Layout>
      <NestedLayout>{page}</NestedLayout>
    </Layout>
  )
}
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
  // 使用在頁面級別定義的布局(如果可用)
  const getLayout = Component.getLayout || ((page) => page)
  return getLayout(<Component {...pageProps} />)
}

數(shù)據(jù)請求

// components/layout.js
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'

export default function Layout({ children }) {
  const { data, error } = useSWR('/api/navigation', fetcher)
  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>
  return (
    <>
      <Navbar links={data.links} />
      <main>{children}</main>
      <Footer />
    </>
  )
}

圖片優(yōu)化

本地圖片

import Image from 'next/image'
import profilePic from '../public/me.png'

function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src={profilePic}
        alt="Picture of the author"
        // width={500} 自動提供
        // height={500} 自動提供
        // blurDataURL="data:..." 自動提供
        // placeholder="blur" // 加載時可選的模糊處理
      />
      <p>Welcome to my homepage!</p>
    </>
  )
}

遠程圖片

import Image from 'next/image'

export default function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src="/me.png"
        alt="Picture of the author"
        width={500}
        height={500}
      />
      <p>Welcome to my homepage!</p>
    </>
  )
}

要使用遠程圖像,src 屬性應該是一個 URL 字符串,可以是相對的也可以是絕對的

Priority

您應該將優(yōu)先級屬性添加到將成為每個頁面的 Largest Contentful Paint (LCP) 元素的圖像。 這樣做允許 Next.js 專門確定要加載的圖像的優(yōu)先級(例如,通過預加載標簽或優(yōu)先級提示),從而顯著提高 LCP

import Image from 'next/image'

export default function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src="/me.png"
        alt="Picture of the author"
        width={500}
        height={500}
        priority
      />
      <p>Welcome to my homepage!</p>
    </>
  )
}

優(yōu)化字體

Google 字體

自動托管任何 Google 字體。 字體包含在部署中,并從與您的部署相同的域提供服務。 瀏覽器不會向 Google 發(fā)送任何請求

// pages/_app.js
import { Inter } from '@next/font/google'

// 如果加載可變字體,則無需指定字體粗細
const inter = Inter({ subsets: ['latin'] })

export default function MyApp({
  Component, pageProps
}) {
  return (
    <main className={inter.className}>
      <Component {...pageProps} />
    </main>
  )
}

指定粗細

如果不能使用可變字體,則需要指定粗細:

// pages/_app.js
import { Roboto } from '@next/font/google'

const roboto = Roboto({
  weight: '400',
  subsets: ['latin'],
})

export default function MyApp({
  Component, pageProps
}) {
  return (
    <main className={roboto.className}>
      <Component {...pageProps} />
    </main>
  )
}

數(shù)組指定多個 weight 或 style

const roboto = Roboto({
  weight: ['400', '700'],
  style: ['normal', 'italic'],
  subsets: ['latin'],
})

在 <head> 中應用字體

// pages/_app.js
import { Inter } from '@next/font/google'
const inter = Inter({ subsets: ['latin'] })
export default function MyApp({ Component, pageProps }) {
  return (
    <>
      <style jsx global>{`
        html {
          font-family: ${inter.style.fontFamily};
        }
      `}</style>
      <Component {...pageProps} />
    </>
  )
}

單頁使用

// pages/index.js
import { Inter } from '@next/font/google'

const inter = Inter({ subsets: ['latin'] })

export default function Home() {
  return (
    <div className={inter.className}>
      <p>Hello World</p>
    </div>
  )
}

指定一個子集

// pages/_app.js
const inter = Inter({ subsets: ['latin'] })

next.config.js 中全局使用所有字體

// next.config.js
module.exports = {
  experimental: {
    fontLoaders: [
      {
        loader: '@next/font/google',
        options: { subsets: ['latin'] }
      },
    ],
  },
}

如果兩者都配置,則使用函數(shù)調用中的子集

本地字體

// pages/_app.js
import localFont from '@next/font/local'

// 字體文件可以位于“pages”內
const myFont = localFont({
  src: './my-font.woff2'
})

export default function MyApp({
  Component, pageProps
}) {
  return (
    <main className={myFont.className}>
      <Component {...pageProps} />
    </main>
  )
}

如果要為單個字體系列使用多個文件,src 可以是一個數(shù)組:

const roboto = localFont({
  src: [
    {
      path: './Roboto-Regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: './Roboto-Italic.woff2',
      weight: '400',
      style: 'italic',
    },
    {
      path: './Roboto-Bold.woff2',
      weight: '700',
      style: 'normal',
    },
    {
      path: './Roboto-BoldItalic.woff2',
      weight: '700',
      style: 'italic',
    },
  ],
})

使用 Tailwind CSS

// pages/_app.js
import { Inter } from '@next/font/google'
const inter = Inter({
  subsets: ['latin'],
  variable: '--font-inter',
});
export default function MyApp({ Component, pageProps }) {
  return (
    <main className={`${inter.variable} font-sans`}>
      <Component {...pageProps} />
    </main>
  )
}

最后,將 CSS 變量添加到您的 Tailwind CSS 配置中:

// tailwind.config.js
const { fontFamily } = require('tailwindcss/defaultTheme')

module.exports = {
  content: [
    './pages/**/*.{js,ts,jsx,tsx}',
    './components/**/*.{js,ts,jsx,tsx}',
  ],
  theme: {
    extend: {
      fontFamily: {
        sans: ['var(--font-inter)', ...fontFamily.sans],
      },
    },
  },
  plugins: [],
}

優(yōu)化 Scripts

頁面腳本

import Script from 'next/script'

export default function Dashboard() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
      />
    </>
  )
}

App 腳本

要為所有路由加載第三方腳本,導入 next/script 并將腳本直接包含在 pages/_app.js

import Script from 'next/script'

export default function MyApp({
  Component, pageProps
}) {
  return (
    <>
      <Script
        src="https://example.com/script.js"
      />
      <Component {...pageProps} />
    </>
  )
}

將腳本卸載到 Web Worker(實驗性的)

此策略仍處于試驗階段,只有在 next.config.js 中啟用了 nextScriptWorkers 標志時才能使用:

module.exports = {
  experimental: {
    nextScriptWorkers: true,
  },
}

設置完成后,定義 strategy="worker" 將自動在您的應用程序中實例化 Partytown 并將腳本卸載到網(wǎng)絡工作者

import Script from 'next/script'

export default function Home() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        strategy="worker"
      />
    </>
  )
}

其他屬性

import Script from 'next/script'

export default function Page() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        id="example-script"
        nonce="XUENAJFW"
        data-test="script"
      />
    </>
  )
}

內聯(lián)腳本

<Script id="show-banner">
  {`document.getElementById('banner').classList.remove('hidden')`}
</Script>
<Script
  id="show-banner"
  dangerouslySetInnerHTML={{
    __html: `document.getElementById('banner').classList.remove('hidden')`,
  }}
/>

執(zhí)行附加代碼

import Script from 'next/script'

export default function Page() {
  return (
    <>
      <Script
        src="https://example.com/script.js"
        onLoad={() => {
          console.log('Script has loaded')
        }}
      />
    </>
  )
}

ESLint

集成 ESLint

"scripts": {
  "lint": "next lint"
}

然后運行 npm run lintyarn lint

yarn lint
# 你會看到這樣的提示:
#
# ? 您想如何配置 ESLint?
#
# ?   基本配置 + Core Web Vitals 規(guī)則集(推薦)
#     基本配置
#     None

Strict

Strict 嚴格配置:包括 Next.js 的基本 ESLint 配置以及更嚴格的 Core Web Vitals 規(guī)則集

{
  "extends": "next/core-web-vitals"
}

Base 基礎配置:包括 Next.js 的基本 ESLint 配置

{
  "extends": "next"
}

項目的根目錄中創(chuàng)建一個包含所選配置的 .eslintrc.json 文件

自定義設置

{
  "extends": "next",
  "settings": {
    "next": {
      "rootDir": "packages/my-app/"
    }
  }
}

rootDir 可以是路徑(相對或絕對)、glob(即“packages/*/”)或路徑和/或 glob 數(shù)組

對自定義目錄和文件進行檢查

module.exports = {
  eslint: {
    dirs: ['pages', 'utils'],
  },
}

在生產(chǎn)構建期間(next build)僅在“pages”和“utils”目錄上運行 ESLint,或者使用命令

$ next lint --dir pages --dir utils --file bar.js

禁用規(guī)則

您可以使用 .eslintrc 中的 rules 屬性直接更改它們:

{
  "extends": "next",
  "rules": {
    "react/no-unescaped-entities": "off",
    "@next/next/no-page-custom-font": "off"
  }
}

修改或禁用受支持的插件(react、react-hooks、next)提供的任何規(guī)則

Core Web Vitals

{
  "extends": "next/core-web-vitals"
}

Prettier

npm install -S eslint-config-prettier
# or
yarn add --dev eslint-config-prettier

{
  "extends": ["next", "prettier"]
}

lint-staged

const path = require('path')

const buildEslintCommand = (filenames) =>
  `next lint --fix --file ${filenames
    .map((f) => path.relative(process.cwd(), f))
    .join(' --file ')}`;

module.exports = {
  '*.{js,jsx,ts,tsx}': [buildEslintCommand],
}

內容添加到項目根目錄中的 .lintstagedrc.js 文件中,以指定 --file 標志

TypeScript

create-next-app

npx create-next-app@latest --ts
# or
yarn create next-app --typescript
# or
pnpm create next-app --ts

靜態(tài)生成和服務端渲染

import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'
export const getStaticProps: GetStaticProps = async (context) => {
  // ...
}
export const getStaticPaths: GetStaticPaths = async () => {
  // ...
}
export const getServerSideProps: GetServerSideProps = async (context) => {
  // ...
}

現(xiàn)有項目添加 ts 配置

touch tsconfig.json

您還可以通過在 next.config.js 文件中設置 typescript.tsconfigPath 屬性來提供 tsconfig.json 文件的相對路徑

API 路由

import type {
  NextApiRequest, NextApiResponse
} from 'next'

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

您還可以鍵入響應數(shù)據(jù):

import type {
  NextApiRequest, NextApiResponse
} from 'next'

type Data = {
  name: string
}

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

自定義應用

使用內置類型 AppProps 并將文件名更改為 ./pages/_app.tsx,如下所示:

import type { AppProps } from 'next/app'

export default function MyApp({
  Component, pageProps
}: AppProps) {
  return <Component {...pageProps} />
}

類型檢查 next.config.js

// @ts-check
/**
 * @type {import('next').NextConfig}
 **/
const nextConfig = {
  /* 配置選項在這里 */
}

module.exports = nextConfig

忽略 TypeScript 錯誤

module.exports = {
  typescript: {
    ignoreBuildErrors: true,
  },
}

危險地允許生產(chǎn)構建成功完成,即使您的項目有類型錯誤

環(huán)境變量

加載環(huán)境變量

將環(huán)境變量從 .env.local 加載到 process.env

DB_HOST=localhost
DB_USER=myuser
DB_PASS=mypassword

使用環(huán)境變量

// pages/index.js
export async function getStaticProps() {
  const db = await myDB.connect({
    host: process.env.DB_HOST,
    username: process.env.DB_USER,
    password: process.env.DB_PASS,
  })
  // ...
}

自動擴展 .env* 文件中的變量

# .env
HOSTNAME=localhost
PORT=8080
HOST=http://$HOSTNAME:$PORT

如果您嘗試使用實際值中帶有 $ 的變量,則需要像這樣對其進行轉義:\$

# .env
A=abc

# becomes "preabc"
WRONG=pre$A

# becomes "pre$A"
CORRECT=pre\$A

向瀏覽器公開環(huán)境變量

為了向瀏覽器公開變量,您必須在變量前加上 NEXT_PUBLIC_ 前綴

NEXT_PUBLIC_ANALYTICS_ID=abcdefghijk

NEXT_PUBLIC_ANALYTICS_ID 可以在此處使用,因為它的前綴是 NEXT_PUBLIC_

// pages/index.js
import setupAnalyticsService from '../lib/my-analytics-service'

//
// 它將在構建時轉換為 `setupAnalyticsService('abcdefghijk')`
setupAnalyticsService(process.env.NEXT_PUBLIC_ANALYTICS_ID)

function HomePage() {
  return <h1>Hello World</h1>
}

export default HomePage

路由

介紹

路由器將自動將名為 index 的文件路由到目錄的根目錄

:----
pages/index.js/
pages/blog/index.js/blog

路由器支持嵌套文件。如果創(chuàng)建嵌套文件夾結構,文件將以同樣的方式自動路由

:----
pages/blog/first-post.js/blog/first-post
pages/dashboard/settings/username.js/dashboard/settings/username

動態(tài)路由

:----
pages/blog/[slug].js/blog/:slug (/blog/hello-world)
pages/[username]/settings.js/:username/settings (/foo/settings)
pages/post/[...all].js/post/* (/post/2020/id/title)

具有動態(tài)路由的頁面

如果您創(chuàng)建一個名為 pages/posts/[pid].js 的文件,那么它可以在 posts/1、posts/2 等處訪問

import { useRouter } from 'next/router'

const Post = () => {
  const router = useRouter()
  const { pid } = router.query

  return <p>Post: {pid}</p>
}

export default Post

使用 useRouter 獲取動態(tài)路由參數(shù) pid

頁面之間的鏈接

import Link from 'next/link'

export default function Home() {
  return (
    <ul>
      <li>
        <Link href="/">首頁</Link>
      </li>
      <li>
        <Link href="/about">關于我們</Link>
      </li>
      <li>
        <Link href="/blog/hello-world">
          博文
        </Link>
      </li>
    </ul>
  )
}

:----
/pages/index.js
/aboutpages/about.js
/blog/hello-worldpages/blog/[slug].js

鏈接到動態(tài)路徑

import Link from 'next/link'

export default function Posts({ posts }) {
  return (
    <Link href={`/blog/${encodeURIComponent(post.slug)}`}>
      標題
    </Link>
  )
}

URL 對象

import Link from 'next/link'

export default function Posts({ posts }) {
  return (
    <Link
      href={{
        pathname: '/blog/[slug]',
        query: { slug: posts.slug },
      }}
    >
      標題
    </Link>
  )
}

動態(tài)路由

考慮以下頁面 pages/post/[pid].js

import { useRouter } from 'next/router'

const Post = () => {
  const router = useRouter()
  const { pid } = router.query

  return <p>Post: {pid}</p>
}

export default Post

到動態(tài)路由的客戶端導航由 next/link 處理

import Link from 'next/link'

export default function Home() {
  return (
    <div>
      <Link href="/post/abc">
        轉到 pages/post/[pid].js
      </Link>
      <Link href="/post/abc?foo=bar">
        也轉到 pages/post/[pid].js
      </Link>
      <Link href="/post/abc/a-comment">
        轉到 pages/post/[pid]/[comment].js
      </Link>
    </div>
  )
}

多個動態(tài)路由

工作方式相同。 頁面 pages/post/[pid]/[comment].js 將匹配路由 /post/abc/a-comment 并且它的查詢對象將是:

{ "pid": "abc", "comment": "a-comment" }

捕捉所有路由

可以通過在括號內添加三個點 (...) 來擴展動態(tài)路由以捕獲所有路徑,pages/post/[...slug].js 匹配 /post/a,也匹配 /post/a/b/post/a/b/c

// /post/a
{ "slug": ["a"] }

// /post/a/b
{ "slug": ["a", "b"] }

可選捕獲所有路由

使用 [[...slug]],pages/post/[[...slug]].js 將匹配 /post/post/a、/post/a/b

// GET `/post` (empty object)
{ }
// `GET /post/a` (single-element array)
{ "slug": ["a"] }
// `GET /post/a/b` (multi-element array)
{ "slug": ["a", "b"] }

事件執(zhí)行調整頁面

import { useRouter } from 'next/router'

export default function ReadMore() {
  const router = useRouter()

  return (
    <button
      onClick={() => router.push('/about')}
    >
      點擊這里閱讀更多
    </button>
  )
}

淺路由

import { useEffect } from 'react'
import { useRouter } from 'next/router'

// 當前網(wǎng)址為“/”
export default function Page() {
  const router = useRouter()

  useEffect(() => {
    // 始終在第一次渲染后進行導航
    router.push('/?counter=10', undefined, { shallow: true })
  }, [])

  useEffect(() => {
    // counter 變了!
  }, [router.query.counter])
}

注意事項

淺路由僅適用于當前頁面中的 URL 更改。 例如,假設我們有另一個名為 pages/about.js 的頁面,并且您運行以下命令:

router.push('/?counter=10', '/about?counter=10', { shallow: true })

由于這是一個新頁面,它會卸載當前頁面,加載新頁面并等待數(shù)據(jù)獲取,即使我們要求進行淺層路由