phymooc / learn-react

0 stars 0 forks source link

Next.js Routing #5

Open phymo opened 1 month ago

phymo commented 1 month ago

Structure

phymo commented 1 month ago

App Router

route groups:

image

private folders

image

dynamic routes

app/blog/[slug]/page.tsx

export default function Page({ params }: { params: { slug: string } }) {
  return <div>My Post: {params.slug}</div>
}

parallel routes

image

However, slots are not route segments and do not affect the URL structure. For example, for /@analytics/views, the URL will be /views since @analytics is a slot.

intercepting routes:

Intercepting routes can be defined with the (..) convention, which is similar to relative path convention ../ but for segments.

You can use:

(.) to match segments on the same level (..) to match segments one level above (..)(..) to match segments two levels above (...) to match segments from the root app directory

image

Route handlers

image

// app/api/route.ts
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET(request: Request) {}

caching/cookie/headers/streaming/cors

export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
phymo commented 1 month ago

The React components defined in special files of a route segment are rendered in a specific hierarchy: image

phymo commented 1 month ago

Link & Navigating

  1. Link Component
    'use client' 
    import { usePathname } from 'next/navigation'
    import Link from 'next/link'
    export default function Page() {
      const pathname = usePathname()
      return <Link href="/dashboard" scroll={false}>Dashboard</Link> // scroll={false} 切换时不保留 scroll位置
    }
  2. useRouter() hook
     'use client'
     import { useRouter } from 'next/navigation'
     export default function Page() {
    const router = useRouter()
    return (
        <button type="button" onClick={() => router.push('/dashboard')}>
          Dashboard
        </button>
      )
    }

    Recommendation: Use the component to navigate between routes unless you have a specific requirement for using useRouter.

redirect

  1. redirect function: 307/303
  2. permanantRedirect: 308
  3. useRouter
  4. redirects in next.config.js
  5. NextResponse.redirect
phymo commented 1 month ago

Error Handling

image

To specifically handle errors in these root components, use a variation of error.js called app/global-error.js located in the root app directory.

app/global-error.tsx

'use client'

export default function GlobalError({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  return (
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => reset()}>Try again</button>
      </body>
    </html>
  )
}
phymo commented 1 month ago

Streaming

SSR procedure

image

SSR limitation

These steps are sequential and blocking, meaning the server can only render the HTML for a page once all the data has been fetched. And, on the client, React can only hydrate the UI once the code for all components in the page has been downloaded.

Streaming comes

Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client. This enables parts of the page to be displayed sooner, without waiting for all the data to load before any UI can be rendered. image

import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'

export default function Posts() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
    </section>
  )
}
phymo commented 1 month ago

Middleware

Use the file middleware.ts (or .js) in the root of your project to define Middleware.

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}

// See "Matching Paths" below to learn more
export const config = {
  matcher: '/about/:path*',
}