nextjs 学习笔记

128 阅读2分钟

文件系统

App Router VS Page Router

nextjs 13起,使用新的路由模式——App Router

  • 区别:

    • Page Router 有缺陷,pages 目录下的文件会被当做路由文件,导致不能很好的组织代码。
    • App Router 约定了特殊文件,在目录中使用特殊的字符可以更好的组织代码;
  • 可以共存,但是App Router的优先级更高。

App router

  • Routes
  • Pages
  • Layouts
  • Templates
  • Loading UI
  • Error Handling
  • 404

定义路由

用文件夹来定义路由 app/home , 对应的路由地址就是 /home ;以下定义了路由 /home

// app/home/page.tsx

export default function Page() {
  return (
    <h1> hello world </h1>
  )
}

定义页面

在文件夹下创建 page.tsx;

// app/home/page.tsx

export default function Page() {
  return (
    <h1> hello world </h1>
  )
}

如果是路由是 /about,则在 app 目录下新建 about文件夹,about 下,新建page.tsx文件即可

定义布局

  1. 在文件夹下创建 layout.tsx;

  2. app 目录下的 layout.tsx 叫做根布局,必须包含 htmlbody,且这个文件必须存在;

  3. 根布局是服务端组件,且不可设置为客户端组件;

  4. 可以嵌套布局文件,比如在 app/menu/layout.tsx 下,那 menu 下的所有页面都会共享该目录下的布局文件;

  5. 布局文件会保持状态不被刷新,与 template.tsx 不同;

import { Inter } from 'next/font/google'
import './globals.css'
import Link from 'next/link'

const inter = Inter({ subsets: ['latin'] })
// app/layout.tsx

export default function RootLayout({
  children
}: Readonly<{
  children: React.ReactNode
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <div>
          <Link href="/about">About</Link>
          <Link href="/settings">Setting</Link>
        </div>
        {children}
      </body>
    </html>
  )
}

定义模板

  1. 在文件夹下创建 template.tsx;

  2. 写法都跟 layout.tsx 一样,但是 template.tsx 不会维持状态;

'use client'
// app/template.tsx

import { ReactNode, useEffect, useState } from 'react'

export default function Template({ children }: { children: ReactNode }) {
  const [count, setCount] = useState<number>(0)

  return (
    <div>
      <div>template: {count}</div>
      <button
        onClick={() => {
          setCount(count + 1)
        }}
      >
        Increment
      </button>
      <div>{children}</div>
    </div>
  )
}

  1. 所以选择 layout 还是 template,要看使用场景,比如依赖useEffect,useState,要保持表单状态,情况下使用 template 更合适

定义加载界面

  1. 在文件夹下创建 loading.tsx;

  2. 实现原理其实是使用了react的 Suspense, ProfilePage 会 throw 一个数据加载的 promise,Suspense 会捕获这个 promise,追加一个 then 函数,then 函数中实现替换 fallback UI 。当数据加载完毕,promise 进入 resolve 状态,then 函数执行,于是更新替换 fallback UI;

// app/loading.tsx

export default function Loading() {
  return <>Loading ...</>
}


// app/page.tsx
async function getData() {
  await new Promise((resolve) => setTimeout(resolve, 3000))
  return {
    message: 'Hello, Dashboard!',
  }
}
export default async function DashboardPage(props) {
  const { message } = await getData()
  return <h1>{message}</h1>
}}

定义错误处理

在文件夹下创建 error.tsx

定义404页面

在文件夹下创建 404.tsx