ByteNoteByteNote

字节笔记本

2026年7月19日

Next.js Link and Script Components: What You Need to Know

API中转
¥120

Next.js provides two built-in components that handle things most developers eventually need: <Link> for client-side navigation and <Script> for loading third-party JavaScript. Both have configuration options that are easy to overlook but make a real difference in how your app performs.

Link Component

<Link> wraps an <a> tag and adds client-side routing, prefetching, and scroll management on top.

Basic Usage

jsx
import Link from 'next/link'

export default function Page() {
  return <Link href="/dashboard">Dashboard</Link>
</export>

Prefetching

By default, <Link> prefetches the linked page's data when it enters the viewport. This makes navigation feel instant but can increase bandwidth usage for pages with lots of links.

Disable it when the target page is heavy or rarely visited:

jsx
<Link href="/admin/reports" prefetch={false}>Reports</Link>

Replace vs Push

Use replace to prevent the linked page from being added to the browser's history stack:

jsx
<Link href="/redirected-page" replace>Go</Link>

This is useful for redirects where you don't want the user pressing Back to land on the redirect page again.

Dynamic Routes

jsx
function BlogList({ posts }) {
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

Scroll Behavior

Control whether the page scrolls to the top on navigation:

jsx
<Link href="/section" scroll={false}>Go to section (no scroll)</Link>

Script Component

<Script> loads third-party JavaScript (analytics, chat widgets, maps) with controlled timing. Uncontrolled <script> tags in your HTML can block rendering — <Script> gives you four strategies to avoid that.

Loading Strategies

jsx
import Script from 'next/script'

// Loads before the page becomes interactive. Use sparingly.
<Script src="/critical.js" strategy="beforeInteractive" />

// Default. Loads after the page is hydrated.
<Script src="/analytics.js" strategy="afterInteractive" />

// Loads during browser idle time. Lowest priority.
<Script src="/chat-widget.js" strategy="lazyOnload" />

// Runs in a Web Worker. Experimental.
<Script src="/heavy-computation.js" strategy="worker" />

For most third-party scripts, afterInteractive is the right choice. Use lazyOnload for non-essential features like chat widgets or heatmaps.

Inline Scripts

Some analytics tools need inline script blocks:

jsx
<Script id="google-analytics" strategy="afterInteractive">
  {`
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', 'G-XXXXXXXXXX');
  `}
</Script>

Lifecycle Events

jsx
<Script
  src="https://maps.example.com/api.js"
  onLoad={() => console.log('Script loaded')}
  onReady={() => console.log('Script ready')}
  onError={(e) => console.log('Script failed:', e)}
/>

onLoad fires when the script tag has loaded. onReady fires after the script has executed and is available for use.

Skip in Development

No reason to send analytics events during development:

jsx
export default function Analytics() {
  if (process.env.NODE_ENV !== 'production') return null

  return (
    <>
      <Script src="https://www.googletagmanager.com/gtag/js?id=G-XXX" strategy="afterInteractive" />
      <Script id="ga-init" strategy="afterInteractive">
        {`gtag('config', 'G-XXX');`}
      </Script>
    </>
  )
}

Putting It Together

A common pattern is loading analytics in the root layout so they run on every page:

jsx
// app/layout.jsx
import Script from 'next/script'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="/analytics.js" strategy="afterInteractive" />
      </body>
    </html>
  )
}

Keep analytics <Script> tags in the root layout rather than individual pages. This ensures consistent tracking and avoids duplicate script loads.

分享: