后端转全栈之Next.js文件约定

本文概括

  • Page Router vs App Router :老版用 pages 目录,新版用 app 目录并通过约定文件定义路由和特殊功能。
  • page.tsx:定义具体页面,对应一个路由。
  • layout.tsx :定义可复用的页面布局,子页面会被包裹其中,根布局必须包含 htmlbody
  • template.tsx:类似布局但不会保留状态,每次路由切换都会重新渲染。
  • loading.tsx:在页面数据加载时显示的过渡界面。
  • error.tsx :客户端错误边界组件,捕获运行时错误并支持 reset 重试。
  • global-error.tsx:根目录的全局错误捕获页面。
  • not-found.tsx :定义 404 页面,用于未匹配路由或显式调用 notFound()

老版本的Next.js使用的是Page Router,在 pages 目录下,每个js文件就是一个路由,这就导致一些组件不能写在 pages 目录下,新版本换成了App Router ,文件放在 app目录下,目录下的 page.tsx 就是代表一个路由,Next.js约定了一些特殊的文件:

布局(layout.tsx)、模板(template.tsx)、加载状态(loading.tsx)、错误处理(error.tsx)、404(not-found.tsx)页面(page.tsx)

页面page.tsx

每个目录下的 page.tsx 会映射到一个路由,需要导出一个默认函数,例如:

javascript 复制代码
export default function Page(){
	return <>Next.js</>
}

布局layout.tsx

layout.tsx 文件导出一个React组件,接受 chidren 作为参数,表示的是子页面内容,子页面会拥有layout里的布局,也就是layout会包裹着page页面

javascript 复制代码
export default function Layout({ children }: { children: React.ReactNode }) {
    return (
        <div>
            <h1>Test Layout</h1>
            {children}
        </div>
    )
}

根布局要求:

  • 必须有根布局 app/layout.tsx
  • 必须包含 htmlbody 标签

模版template.tsx

模版和layout类似,会包裹每个页面,但是和layout的区别是,模版不会维持状态,每次进入一个新的路由都会重新初始化,模版会被layout包裹起来。

例如在layout文件里写一个 表单,那么通过Link跳转到子路由,表单里的内容不会变,如果是使用template,那么就会重新渲染,表单里的数据消失

例如 layout.tsx

javascript 复制代码
'use client'
import React, { useState } from 'react'

export default function Layout({ children }: { children: React.ReactNode }) {
    const [count, setCount] = useState(0)

    return (
        <div>
            <h1>Test Layout</h1>
            <>Layout Count: {count}</>
            <button onClick={() => setCount(count + 1)}>Layout数字增加</button>
            <br />
            {children}
        </div>
    )
}

template.tsx

javascript 复制代码
'use client'
import React, { useState } from 'react'
export default function Template({ children }: { children: React.ReactNode }) {
    const [count, setCount] = useState(0)

    return (
        <div>
            <>Template Count: {count}</>
            <h1>Test Template</h1>
            <button onClick={() => setCount(count + 1)}>Template数字增加</button>
            {children}
        </div>
    )
}

当我们增加了数字之后,在test目录路由下跳转,会发现layout里的数字不变,template里的数字会清空

加载loading.tsx

loading.tsx 是加载页面,例如:

javascript 复制代码
export default function Loading() {
    return (
        <div>
            <h1>Loading</h1>
        </div>
    )
}

这样在 page.tsx 加载数据的时候,在没拿到数据之前,就会显示loading的内容:

javascript 复制代码
import Link from 'next/link'

async function getUser() {
    await new Promise((resolve) => setTimeout(resolve, 2000))
    return {
        name: 'cxk',
    }
}

export default async function Page() {
    const { name } = await getUser()
    return (
        <div>
            <Link href="/test/test2">跳转Page2</Link>
            <Link href="/test">跳转Page</Link>
            {name}
        </div>
    )
}

如果一个目录下有很多约定的文件,那么他们的层级是:

nextjs.org/docs/app/ge...

Next.js文件约定

错误error.tsx

错误页面必须是客户端组件, error.tsx 接受一个error和reset

  • error: Error

    捕获到的错误对象,可能带 digest(Next.js 内部生成的唯一标识符)。

  • reset: () => void

    调用它可以 重置错误边界,让 Next.js 重新尝试渲染页面(比如在用户点 "Retry" 按钮时)。

javascript 复制代码
'use client'

export default function Error({ error, reset }: { error: Error; reset: () => void }) {
    const handleReset = () => {
        console.log('reset')
        reset()
    }
    return (
        <div>
            <h1>Error</h1>
            <p>{error.message}</p>
            <button onClick={handleReset}>Reset</button>
        </div>
    )
}

可以在页面获取数据的时候抛出异常试试:

javascript 复制代码
async function getUser() {
    await new Promise((resolve) => setTimeout(resolve, 2000))
    throw new Error('test error')
    return {
        name: 'cxk',
    }
}

export default async function Page() {
    const { name } = await getUser()
    return (
        <div>
            <Link href="/test/test2">跳转Page2</Link>
            <Link href="/test">跳转Page</Link>
            {name}
        </div>
    )
}

注意:错误边界不可以捕获同级的layout和tempalte,必须在父级的error.tsx去捕获,因为 ErrorBoundary 被Layout和Template包裹了。

根目录的捕获可以使用 global-error.tsx 进行捕获

404not-found.tsx

未找到页面会显示404页面的内容,触发情况主要有两种:

  • 组件调用 notFound 函数
  • 路由地址不匹配
相关推荐
子兮曰2 小时前
🚀从单体到Monorepo:四川省xxx协会官网架构重生记
前端·next.js·turbopack
却尘4 小时前
React useMemo 依赖陷阱:组件重挂载,状态无限复原
前端·javascript·react.js
Mintopia8 小时前
在 Next.js 中接入 Google Analytics 与 PostHog —— 一场“数据偷窥”的艺术演出
前端·javascript·next.js
遂心_8 小时前
React useState:20分钟彻底掌握这个让你"状态满满"的Hook
前端·javascript·react.js
江城开朗的豌豆9 小时前
Axios拦截器:给你的请求加上"双保险"!
前端·javascript·react.js
江城开朗的豌豆9 小时前
解密DVA:React应用的状态管理利器
前端·javascript·react.js
OEC小胖胖10 小时前
App Router vs. Pages Router:我应该如何选择?
开发语言·前端·前端框架·web·next.js
xiaopengbc1 天前
在 React 中如何使用 useMemo 和 useCallback 优化性能?
前端·javascript·react.js