이 글은 노마드코더 의 Next.js 강의를 기반으로 쓰였습니다.
(강의 바로가기)


Next.js에서 새로운 페이지 만들기

자, 이제 Next.js에서 새로운 페이지를 만들어보자.
라고 하기엔 우린 이미 페이지를 하나 만들었다.
그렇다! 바로 저번 글에서 만든 app/page.tsx 이다!

이렇게 app 안에 만든 page.tsxroot segment라고 부른다.
왜냐면 이것이 유저가 제일 먼저, root(/)에서 볼 페이지, 즉 우리가 만든 애플리케이션의 홈이라는 뜻이다.

이를 확인하기 위해 localhost:3000 뒤에 /를 붙이게 되면 root 화면으로 가게된다.
(지금 친다고 해서 화면에 변화는 없을것이다. 왜냐하면 이미 root 화면이기 때문)

페이지 라우팅하기

그렇다면 만약 about-us 페이지를 만들고 싶다면 어떻게 해야 할까?

이는 굉장히 간단한 방법으로 가능한데, 바로 app 폴더 아래에 about-us 폴더를 새로 만드는 것이다.

이렇게 폴더를 생성함으로써 우리는 Next.js에게 해당 폴더가 잠재적으로 하나의 페이지가 될 수 있다고 알려주는 것이다.
(지금 당장은 페이지가 아니다!)

만약 폴더만 만들고 브라우저에서 localhost:3000/about-us로 접속한다면 해당 주소로 이동은 하지만 404 오류가 나타날것이다.
404오류

그 이유는 아직 우리가 /about-us로 이동했을 때 Next.js가 렌더링할 UI를 제공하지 않았기 때문이다.

그렇다면 어떻게 UI를 제공해 줄 수 있을까?

바로 about-us 폴더에 page.tsx 파일을 만들어주는 것이다.

about-us/page.tsx

export default function AboutUs() {
  return <h1>About Us!</h1>;
}

위와 같이 about-us/page.tsx 파일을 export 해준 후 localhost:3000/about-us 로 접속해보자.
about-us

위와 같이 이제는 404 오류가 나오지 않고 페이지가 잘 나오는 것을 확인할 수 있다.
이렇게 우리는 Next.js에게 애플리케이션의 경로와 그곳이 어떤 페이지인지 알려줌으로써 간단하게 라우팅을 했다.

page.tsx 없는 폴더에 페이지 다시 만들기

그렇다면 만약 page.tsx 를 만들지 않은 폴더 안에 페이지를 생성하면 어떻게 될까?
궁금하니 바로 실험해보도록 하자.

일단 about-us 안에 company 폴더를 만든 후, company 폴더 안에 sales 폴더를 만들자.
그 후, sales 폴더 안에 page.tsx 파일을 만들어 리액트 컴포넌트를 아래와 같이 export 해주자.

about-us/company/sales/page.tsx

export default function Sales() {
  return <h1>Sales Team!!</h1>;
}

그럼 이제 about-ussales 폴더에는 page.tsx 파일이 있지만, company 폴더에는 page.tsx 파일이 없는 상태이다.

자, company 폴더에는 도대체 무슨일이 생긴걸까?

이를 알아보기 전에 우리가 만든 sales/page.tsx 에는 어떻게 접근하는지 먼저 알아보도록 하겠다.
이는 sales/page.tsx의 경로를 생각해보면 알 수 있다.
바로 localhost:3000/about-us/company/sales를 브라우저 주소창에 입력하는 것이다!

Sales 페이지

그렇다면 우리의 첫 번째 궁금증이였던 company에 접근해보도록 하자.
브라우저 주소창에서 localhost:3000/about-us/company를 입력해 접근하려고 하면...

404 오류 페이지가 뜬다!
왜냐하면 comapny 폴더에는 page.tsx 파일이 없기 때문이다.
그렇기 때문에 about-us/company 에서는 아무것도 보여줄 것이 없어 404 오류 페이지가 뜨게 되는것이다.

즉, 우리가 만든 about-uscompany , sales 등의 폴더들은 모두 url을 생성하기 위한것이라는 뜻이다.

폴더들은 url의 한 부분인 것이지 실제로 보여지는 페이지가 아니며, 실제로 보여지는 페이지를 만들기 위해서는 page 파일을 폴더 내부에 생성해야 한다!

그러니까 여기서 company 폴더는 실제 페이지 없이 그저 경로의 일부분이 될 뿐이라는 것!

그럼 이제 company 폴더 안에도 page.tsx 파일을 만들어주자.

about-us/company/page.tsx

export default function Company() {
  return <h1>Company page ~</h1>;
}

위와 같이 page.tsx 파일을 만들어준 후 다시 브라우저를 확인해보면

페이지가 잘 나오는 것을 확인 할 수 있다.

app 폴더에 다른 파일 만들어보기

그렇다면 app 폴더에 다른 파일을 만들어도 될까?
정답은.. 그럴 수 있다.

왜냐면 page라는 파일을 만들지 않는 이상 실제 경로에 포함되지도, 렌더링되지도 않기 때문이다.

page가 아닌 다른 파일 렌더링 시켜보기

그렇다면 만약 다른 파일을 렌더링 시키고 싶다면 어떻게 할 수 있을까?
직접 한번 해보도록 하자.

일단 app 폴더에 components 폴더를 생성해준다.
그 후 components 폴더 안에 avatar.tsx 라는 파일을 생성해주고, export 해준다.

components/avatar.tsx

export default function Avatar() {
  return <h1>It's Avatar Component</h1>;
}

당연히도 현재 이 폴더는 page 파일을 가지고 있지 않기 때문에 렌더링되지 않는다.
따라서 이 폴더는 그저 컴포넌트들을 가지고 있는 일반적인 폴더이다.

about-us/company/sales/page.tsx

import Avatar from "../../../components/avatar";
export default function sales() {
  return <Avatar />;
}

하지만 sales 에서 avatar 를 위와 같이 불러와서 사용할 수 있다.

다시 브라우저를 확인해보면 페이지가 바뀌어 있는 모습을 확인 할 수 있다.

components 폴더의 avatar.tsx 파일은 page.tsx 에서 import 해서 브라우저에 그려지긴 하지만 url은 될 수 없는것이다.

  • 자, 이제 다음단계를 밟기 전에, 필요없는 페이지를 지워주도록 하자.
    about-us 페이지를 제외한 company, sales, components 폴더와 하위 파일들을 지워주었다.

Not Found 페이지 만들기

이번에 만들 페이지는 Not Found 페이지이다.
우리가 위에서 page.tsx가 없는 페이지로 접근하려고 하면 404 오류 페이지가 나타나는 것을 볼 수 있었을 것이다.

우리는 이 페이지를 따로 만들어 관리해보도록 하자.

일단 app 폴더 아래에 not-found.tsx 파일을 새로 만들어준다.

not-found.tsx

export default function NotFound() {
  return (
    <div>
      <h1>Not Found!!!</h1>
    </div>
  );
}

그 후 위와 같이 export 해주고, 브라우저 주소창에 존재하지 않는 경로로 접근해보자.

위와 같이 not-found 페이지가 잘 나오게 된다.

네비게이션 바 만들기

이제 대부분의 웹 페이지에 있는 네비게이션 바를 만들어보자.

일단 app/components/navigation.tsx 파일을 생성해주겠다.
( app 폴더 > components 폴더 > navigation.tsx )

components/navigation.tsx

import Link from "next/link";

export default function Navigation() {
  return (
    <nav>
      <ul>
        <li>
          <Link href="/">Home</Link>
        </li>
        <li>
          <Link href="about-us">About Us</Link>
        </li>
      </ul>
    </nav>
  );
}

위와 같이 export 해주면 일단은 우리의 네비게이션 바를 만들어주게 됐다.
이 때, 자세히 봐야할 것은 <Link> 태그인데, 이는 Next.js에서 제공하는 <a> 태그의 역할을 해줄 녀석이다.

<Link> 태그의 사용법은 간단한데, 태그 안에 href 경로를 입력시켜주면 된다.

그럼 어떤 경로를 적으면 되는걸까?

그건 본인이 원하는 페이지의 경로를 적어주면 된다!

예를들어 about-us 페이지로 이동시키고 싶다면 about-us 페이지의 경로인 <Link href="/about-us"> 라고 적어주는 것이다.

자, 이제 네비게이션 바 페이지를 만들어 주었으니, 각 페이지에 네비게이션 페이지를 추가해주도록 하자.

/page.tsx

import Navigation from "./components/navigation";

export default function Page() {
  return (
    <div>
      <Navigation />
      <h1>Hello!!!</h1>
    </div>
  );
}

about-us/page.tsx

import Navigation from "../components/navigation";

export default function AboutUs() {
  return (
    <div>
      <Navigation />
      <h1>About Us!</h1>
    </div>
  );
}

/not-found.tsx

import Navigation from "./components/navigation";

export default function NotFound() {
  return (
    <div>
      <Navigation />
      <h1>Not Found!!!</h1>
    </div>
  );
}

자, 이제 브라우저를 확인해보면..

모든 페이지 상단에 우리가 만든 네비게이션 바가 추가된 것을 확인할 수 있다!

그런데... 이런 방식으로 페이지가 추가될때 마다 위에 네비게이션 바를 추가해줘야 하는걸까 ??
만약 그렇다면 너무나도 귀찮은 작업이 될것이다.

다행히 다른 방법이 있지만 페이지가 많지 않기도 하고, 우리는 아직 방법을 알지 못하니 일단 네비게이션 바에 집중해보도록 하자.
(내일의 나에게 미루도록 하자?)

네비게이션 바에 현재 위치 표시하기

usePathname

자, 이제 우리는 우리가 어디에 있는지 편하게 확인하고 싶기 때문에 현재 위치에 이모지를 사용해 간단하게 표시를 해보도록 하겟다.

일단 components/navigation.tsx 로 이동해 경로명을 알려주는 hook을 사용해 볼 예정이다.

Next.js 는 아주 멋진 프레임워크이기 때문에 우리에게 url 정보를 알려주는 hook들이 존재한다.
그 중 우리가 이번에 사용할 hook은 usePathname 이라는 hook이다.

여기서 path name이란?
user가 현재 머물고 있는 url을 뜻한다.
그러니까 user가 현재 "/"에 있는지, "/about-us"에 있는지, "/movie"에 있는지 등을 알려준다.

그럼 이제 usePathname 훅을 사용해보자.

components/navigation.tsx

import Link from "next/link";
import { usePathname } from "next/navigation";
export default function Navigation() {
  const path = usePathname();
  console.log(path)
  return (
    <nav>
      <ul>
        <li>
          <Link href="/">Home</Link>
        </li>
        <li>
          <Link href="about-us">About Us</Link>
        </li>
      </ul>
    </nav>
  );
}

위와 같이 코드를 수정하고, console.log 를 찍어보면...

쨔쟌. 에러가 떠버리고 만다.

엥? 이게 도대체 무슨 오류일까?

일단 에러가 우리에게 뭐라고 하는지 살펴보자.
(에러는 우리에게 많은 것을 가르쳐주기 때문이다)

아무래도 usePathnameClient Componenets 에서만 작동한다고 하는 듯 하다.
그리고 우리는 코드 최상단에 "use client" 라는 문구를 추가해야한다고 한다.

use client

일단 클라이언트 컴포넌트를 알아보기 전에 이녀석이 원하는 대로 "use client" 라는 문구를 추가해 정상적으로 작동하는지 확인해보도록 하자.

오! 아주 정상적으로 작동한다!

그리고 브라우저의 콘솔창을 확인했을 때에도 우리가 적어둔 console.log(path)가 정상적으로 작동하고 있다는 사실도 확인이 가능하다.

이제 우리가 원했던 현재 위치를 이모지로 표시해보도록 하자.

components/navigation.tsx

"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";

export default function Navigation() {
  const path = usePathname();

  return (
    <nav>
      <ul>
        <li>
          <Link href="/">Home</Link>
          {path === "/" ? "❤" : ""}
        </li>
        <li>
          <Link href="about-us">About Us</Link>
          {path === "/about-us" ? "❤" : ""}
        </li>
      </ul>
    </nav>
  );
}

아주 잘 작동하는 것을 볼 수 있다!

왜 작동하는거지? (SSR vs CSR)

우리는 usePahtname 을 사용하려고 했을 때 에러가 발생했고, use client 라는 문구를 상단에 적어주기만 했는데 에러가 사라지면서 페이지가 잘 나타났다.

왜 그런걸까 ?

일단 이를 이해하기 위해서는 Next.js 가 어떤식으로 우리의 애플리케이션을 렌더하는지 알 필요가 있다.

여기서 렌더(render)란?
Next.js 가 우리의 코드 즉, react components 를 가져와서 브라우저가 이해할 수 있는 html로 변환하는 작업을 말한다.

일단 우리의 Next.jsSSR (Server Side Rendering) 방식인데, 이는 우리가 Create-React-App 으로 만든 웹과는 다른 방식으로 작동한다.

SSR을 알아가기 앞서, 평범한 React가 렌더되는 방식인 CSR (Client Side Rendering) 방식부터 알아보자.


CSR 방식

CSR 방식은 브라우저rendering 작업을 해준다.
즉, 사용자 브라우저인 Client 단에서 모든 rendering 작업을 수행해야 한다는 뜻이다.

이 방식에는 아래와 같은 단점이 있다.

1. 페이지의 소스코드를 확인하면 실제 소스코드는 비어있는 것을 확인할 수 있다.

"엥? 하지만 element를 확인해보면 비어있지 않은데?" 라고 할수있지만, 사실 그것들이 처음부터 존재했던 것이 아니다.
그러니까 유저가 해당 페이지에 도착했던 시점에서는 페이지가 비어있는 상태이다.

그렇다면 element에서 확인된 코드들은 도대체 어디서 나온걸까?
이는 브라우저가 Javascript 파일을 다운로드 받고, 실행해서 생겨난 코드들인것이다.
즉, 브라우저의 Javascript 엔진에 의해 추가된 것

이를 확인하는 법은 간단한데, 브라우저에서 새로고침을 눌러보면 순간적으로 깜빡거리며 아무것도 없는 순간을 확인할 수 있다.
그 순간이 지나면 내용이 나타나고, 이 순간이 바로 브라우저가 모든 Javascript 파일을 받고 실행시키는데 걸리는 시간이다.

그렇다면 만약 Javascript를 비활성화 시킨 유저에게는 무슨 일이 일어나는 걸까??

이런식으로 Javascript가 필요하다고 나오며, 우리가 열심히 만든 애플리케이션을 실행시킬수도 없다!!
(물론 Javascript를 비활성화 해두고 사용하는 사람은 거의 없기 때문에 말이 안되는 상황이긴 하다.)

하지만 유저의 인터넷 연결 상태가 좋지 않다면?

브라우저는 우리의 Javascript 파일을 모두 받고, 그것들을 실행시켜서 UI를 그려주기 때문에 아무것도 없는 빈 페이지를 더욱 오래 보고있어야 할것이다.
(이는 굉장히 끔찍한 일이다)

2. SEO 검색엔진 최적화에 적합하지 않다

만약 Google 같은 검색엔진에 우리가 만든 웹이 노출되기를 바란다면 CSR 방식은 적합하지 않을것이다.
왜냐하면 Google은 페이지의 HTML을 보기 때문!

즉, Google은 웹의 빈 HTML을 볼것이고, 우리가 열심히 만들어 둔 웹은 빈 웹이라고 인식할것이다.
(물론 가끔 Javascript를 실행시키기도 하지만 굳이 그런 위험을 감수할 필요는 없다.)


SSR 방식

자, 그럼 이제 Next.js 의 방식인 SSR 에 대해 알아보자.

일단 Next.js 로 웹을 만들게 되면, 자동적으로 Server Side rendering이 된다.

SSR 방식이 좋은 점은 브라우저Javascript를 다운받을 때까지 기다리지 않아도 된다는 점이다!

실제로 소스코드를 확인해보면 페이지의 내용들이 모두 브라우저 코드에 있는것을 볼 수 있다.

이는 사용자의 브라우저가 Javascript를 비활성화 시켜도 HTML을 볼 수 있게 되는 것!

그러니까 Next.js 의 모든 page 안의 모든 component 들은 먼저 server 에서 Rendering 된다는 것이다.

예를들어 사용자가 about-us 로 접속하게 되면 Next.jsserver (즉, backend)에서 우리의 애플리케이션을 render 할 것이다.
그 후 HTML로 변환된 우리의 컴포넌트들을 브라우저가 요청한 것에 대한 response로 줄것이다.

이런 단계를 거치기 때문에 사용자가 about-us 페이지에 접속하더라도 비어있는 HTML을 보지 않는것!

이는 모든 컴포넌트에 대해 발생하게 되는데, 이는 client componentserver component 에 관계없이 발생한다.
심지어 우리가 Navigation에 적었던것 처럼 "use client" 를 가지고 있는 컴포넌트도 예외는 아니다.


정리

  • 렌더링이란?
    컴포넌트들을 브라우저가 이해할 수 있는 HTML로 변환하는 작업

  • CSR
    모든 렌더링이 클라이언트 측에서 발생
    때문에 클라이언트는 자바스크립트를 로드하고, 자바스크립트가 UI를 빌드

  • SSR
    모든 렌더링이 서버 측에서 발생
    때문에 클라이언트가 자바스크립트를 로드할 필요가 없음
    이는 "use client"의 사용 여부와 상관 없음

profile
개념을 이해하고 다른사람에게도 알려줄 수 있는 개발자가 되고 싶어요..

0개의 댓글