본문 바로가기
Front-end/React.js

Next/link, route, <a> 뭐가 어떻게 다른데?

by img 2022. 4. 19.

Next.js를 사용해보다가, <Link>와 Router 의 차이점에 대해서 궁금해져서 알아보았습니다.

<Link href="/about"><a>About me</a></Link>

<a href="/about">About me</a>

<button onClick={() => router.push("/about")}>About me</button>

위 코드들은 겉으로 보기엔 경로이동을 한다는 점에서는 비슷해보이지만, 각자 다른 점이 있습니다. 가장 큰 차이점은 "검색엔진최적화(SEO)"였습니다. 

1. Route

router.push()를 이용하는 경우는 window.location과 비슷하게 동작합니다. <a>태그를 만들지 않기때문에 검색엔진최적화(SEO)을 신경쓰고 있다면(아마 Next.js를 사용하는 이상 대부분 신경을 쓰지 않을까요) 해당 링크는 크롤링되지 않아서 SEO에 불리합니다. 대부분 onClick과 같은 이벤트 핸들러와 같이 사용됩니다. 

2. <Link>

하지만 <Link>태그는 <a>태그를 생성하기 때문에 웹사이트가 크롤링되어 SEO에 유리합니다. 페이지를 다시 로드하지않고 SPA동작처럼 "보이게" 만듭니다. 

 3. <a>

순수 HTML 요소로, 사용자를 새 페이지의 URL로 이동시키는 하이퍼링크를 생성합니다. 이때 페이지는 완전히 새로고침 됩니다. 만약 Next.js에서 <a>를 사용할 일이 있으면 <Link>태그로 바꾸는 것이 좋습니다. (하지만 <Link>가 언제나 <a>태그를 포함하는 것은 아닙니다)

결론 : 웬만하면 <Link>태그를 사용하는 것이 좋으며, SEO에 상관없이 SPA처럼 동작하게 하고싶을 때엔 router.push를 사용합니다. 


- 아래는 라우팅 사용에 대한 공식문서를 번역한 내용입니다. (사용법에 관한 내용입니다)

https://nextjs.org/docs/routing/introduction

 

Routing: Introduction | Next.js

Next.js has a built-in, opinionated, and file-system based Router. You can learn how it works here.

nextjs.org

 

Next.js는 페이지를 기반으로 연결(라우팅)을 하는 파일시스템입니다. 파일이 '/pages'라는 폴더 안에 추가되면, 자동으로 연결(라우팅)이 되는것이죠. 'pages'폴더 안의 파일들은 가장 일반적인 패턴을 만들 때 사용됩니다.

Index 

router는 자동으로 'index'라는 파일을 자동으로 루트 디렉토리에 연결시킵니다.  

  • pages/index.js  /
  • pages/blog/index.js  /blog

중첩 연결

router는 nested 파일(폴더안의 폴더안의 폴더안의 폴더안의.... 파일)에도 사용가능합니다. 만약 중첩된 폴더 구조를 가지고 있따면 파일들은 자동으로 다음과 같이 연결됩니다. 

  • pages/blog/first-post.js  /blog/first-post
  • pages/dashboard/settings/username.js  /dashboard/settings/username

동적 세그먼트 연결

동적으로 연결시키기 위해서는 [대괄호] 문법을 사용해야 합니다. 이렇게 하면 파라미터의 이름으로 연결됩니다. 

  • pages/blog/[slug].js  /blog/:slug (/blog/hello-world)
  • pages/[username]/settings.js  /:username/settings (/foo/settings)
  • pages/post/[...all].js  /post/* (/post/2020/id/title)

페이지간 연결하기

Next.js의 라우터는 SPA처럼 페이지간 이동시에 클라이언트 사이드(CSR)에서 렌더링을 하게 해주는데요. Link라고 불리는 리액트의 컴포넌트가 클라이언트 사이드(CSR)렌더링을 해줍니다. 

import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link href="/">
          <a>Home</a>
        </Link>
      </li>
      <li>
        <Link href="/about">
          <a>About Us</a>
        </Link>
      </li>
      <li>
        <Link href="/blog/hello-world">
          <a>Blog Post</a>
        </Link>
      </li>
    </ul>
  )
}

export default Home

위와 같이 다중으로도 사용합니다. 각각은 href에 연결된 경로를 다음과 같이 연결해줍니다.

  • /  pages/index.js
  • /about  pages/about.js
  • /blog/hello-world  pages/blog/[slug].js

뷰포트 안의 모든 <Link /> 는 디폴트로 static generation을 사용하는 페이지로 prefetch됩니다. (CSR이 아닌) SSR로 라우팅된 데이터는 prefetched 되지 않습니다. 

동적 경로 연결하기

또한 동적 라우팅 경로로 interpolation(객체 안에 들어있는 프로퍼티....쯤으로 해석....) 를 사용할 수도 있습니다. 예를들어서 컴포넌트로 라우팅할 수 있는 글 목록을 보여주기 위해서 다음과 같이 할 수 있습니다 :

import Link from 'next/link'

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

export default Posts

(encodeURIComponent는 경로의 utf-8호환성을 위해 사용되었습니다)

다른방법으론, URL 객체를 사용할 수도 있습니다 : interpolation을 사용하는 대신 href안에서 URL객체를 사용

import Link from 'next/link'

function Posts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <Link
            href={{
              pathname: '/blog/[slug]',
              query: { slug: post.slug },
            }}
          >
            <a>{post.title}</a>
          </Link>
        </li>
      ))}
    </ul>
  )
}

export default Posts
  • pathname은 'pages' 폴더 안에 있는 파일 이름입니다. 여기서는 '/blog/[slug]' 가됩니다.
  • query는 동적 객체입니다. 여기서는 'slug'가됩니다. 

댓글