Next.js学习笔记1 文件系统和路由

175 阅读3分钟

说明

客户端组件和服务端组件是两种组件类型.本文尽可能不涉及相关内容

通过文件系统定义路由

app目录下 页面所处的路径就是它的路由
defining-routes.avif 仅存在page.js或route.js的文件夹被视作合法路由,且两个文件至多存在一个.

page.js

该路由对应的页面内容.应当默认导出一个react组件

export default function Page(){
    return <span>1</span>
}

浏览器访问它对应的路由时 这个组件会被展示

route.js

此文件说明它所处的路由是一个"api",用于处理http请求.

具有特殊含义的文件

除了page.js,route.js,每级路由中还存在一些具有特殊含义的文件.它们应当默认导出一个react组件.它们都不是必需的. file-conventions-component-hierarchy.avif
在访问本级路由时,这个结构会被完整的呈现.如果访问的子路由,则Page会被替换为子路由的完整结构,也包含它自己的Layout,Template等.

Layout和Template

  • 必须存在一个root layout
    app/layout.js必须存在 且应该具有这样的结构
export default function(props){
    return (
        <html>
            <body>
                {/* ... */}
            </body>
        </html>
    )
}
  • Layout和Template所提供的组件需要正确包裹Page
export default function Layout(props:{ children:ReactNode }){
    return (
        <span>{props.children}</span>
    )
}
  • Template总是会重建 而Layout不会
    类似于
<Layout>
  <Template key={routeParam}>{children}</Template>
</Layout>

跳转和重定向

  • Link组件
    用于替代a标签.可以进行预请求
import Link from 'next/link'
 
export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
}

Link的默认行为是滚动到新页面的顶部.可以设置参数scroll=false禁用此行为.

  • useRouter
    仅用于客户端组件.
'use client'
 
import { useRouter } from 'next/navigation'
 
export default function Page() {
  const router = useRouter()
 
  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

router.push的默认行为也是滚动至新页面顶部,可以使用router.push('/dashboard',{scroll:false})禁用这一行为.

  • 重定向
    服务端组件中 使用redirect进行重定向
import { redirect } from 'next/navigation'

// 组件中
redirect('/login')

api路由:route.js

route.js用于next服务端处理http请求.它应当导出GET、POST等一个或多个与http方法同名的函数

export async function GET() {
  const data = 'get'
  return Response.json({ data })
}

更详细的内容查看文档

软导航

url变化时 浏览器进行的是'硬导航',整个页面重新渲染.而next进行的是软导航,可以只重新渲染变化的路由所对应的组件.这有利于上级路由保存state

特殊的路由结构

路由组

route-group-organisation.avif
可以在不影响url的前提下组织路由.
尽管分组的路由不可达 但它的layout.js文件仍然会对它包含的所有页面生效

平行路由(插槽)

parallel-routes-file-system.avif

export default function Layout({
  children,
  team,
  analytics,
}: {
  children: React.ReactNode
  analytics: React.ReactNode
  team: React.ReactNode
}) {
  return (
    <>
      {children}
      {team}
      {analytics}
    </>
  )
}

作用上可以理解为Layout的子组件.平行路由不会体现在url上,但是可以拥有自己的loading.js,error.js等.
平行路由也可以拥有自己的子路由 parallel-routes-unmatched-routes.avif 此时访问'/settings',@team插槽处于active,会相应地显示/app/@team/settings/page.js,但@analytics插槽的状态则不确定.如果是next的软导航 则保留之前的状态 否则显示default.js(没有则会404).
值得注意的是 Layout接受的children参数也可以理解为一个特殊的插槽@children,它在未激活时也需要一个default.js

拦截路由

intercepted-routes-files.avif 直接访问'/photo'时会显示/photo的内容;但从'/feed'跳转至'photo'时,这个url会被拦截,改为显示feed/(..)photo的内容.拦截路由允许同一个url,具有不同的表现,可以用于创建Modal等.
拦截规则如下

  • (.)匹配同一级别的区段
  • (..)匹配上一级的区段
  • (..)(..)匹配上述两个级别的区段
  • (...)匹配目录中的区段app