后端转全栈之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 函数
  • 路由地址不匹配
相关推荐
IT枫斗者5 小时前
前端部署后如何判断“页面是不是最新”?一套可落地的版本检测方案(适配 Vite/Vue/React/任意 SPA)
前端·javascript·vue.js·react.js·架构·bug
倾颜8 小时前
React 19 源码主线拆解 04:Fiber 到底是什么,React 为什么需要 Fiber?
前端·react.js·源码阅读
老王以为10 小时前
为什么 React 和 Vue 不一样?
前端·vue.js·react.js
迪菲赫尔曼13 小时前
从 0 到 1 打造工业级推理控制台:UltraConsole(Ultralytics + FastAPI + React)开源啦!
前端·yolo·react.js·计算机视觉·开源·fastapi
Highcharts.js13 小时前
React 开发实战:如何使用 useEffect 为 Highcharts 注入实时数据
前端·javascript·react.js·开发实战·实时数据·highcharts·轮询数据
光影少年15 小时前
前端SSR和ssg区别
前端·vue.js·人工智能·学习·react.js
祖国的好青年15 小时前
VS Code 搭建 React Native 开发环境(Windows 实战指南)
android·windows·react native·react.js
天天进步201517 小时前
魔音漫创源码解析:架构总览:Electron 30 + React 18 + Zustand,构建桌面级影视生产工具
react.js·架构·electron
kyriewen1119 小时前
Next.js部署:从本地跑得欢,到线上飞得稳
开发语言·前端·javascript·科技·react.js·前端框架·ecmascript
朝阳3919 小时前
react【实战】首页 -- 白天/黑夜主题切换(含组件封装)
前端·react.js·前端框架