꼬드리 2024. 3. 14. 14:54

이번 주부터는 Next.js 프레임워크를 공부해보기로 하였습니다🥰

React만 사용하다가 Next.js로 넘어온 것이라 우선 생활코딩으로 가볍게 살펴본 뒤, 노마드코더의 next.js14버전 강의로 추가 학습했습니다. 아래는 아래 강의를 배우며 정리한 부분입니다. Next.js의 선택적 hydration 및 use client 에 대해 자세하게 알아볼 수 있어서 굉장히 유익했습니다. 

해당 강의 #2.5까지가 이번 포스팅의 범위입니다. 

 

All Courses – 노마드 코더 Nomad Coders

초급부터 고급까지! 니꼬쌤과 함께 풀스택으로 성장하세요!

nomadcoders.co

 

🚩Introduce

Next.js는 풀스택 웹 앱을 개발하기에 있어, 최고의 프레임워크라고 해도 과언이 아니다.

리액트 프레임워크 중에서는 next.js가 현재 1위를 차지했다.

 

🍬React(라이브러리) vs next.js(프레임워크) ?

라이브러리: 내가 원하는 방식으로 사용한다. 코드 내에서 ‘내’가 필요할 때 결정해서 내가 주체적으로 사용하는 원리이다.

프레임워크: 나에게 상대적으로 주도권이 없다. 다만 개발자가 기존까지 일일이 내려야하는 결정들을 자동화하여 훨씬 쉽게 구현할 수 있게 도와준다. 따라서 우리는 미리 정해진 ‘규칙’들을 지켜야 한다.

 

→ next.js는 리액트와 달리, 이러한 규칙이 존재하는 프레임워크다. 따라서 next.js를 사용하기 위해서는 이런 규칙들을 배워야 한다!

 

? 당신이 만약 next js 구버전을 쓰고 있다면?

→ Next.js 14부터 기존 버전과 다르게 새롭게 들어온 기능들이 있다. 특히 app router은 기존의 pages router과 많이 달라졌다. 하지만 당장 전부 마이그레이션 하지 않고 기존의 pages router을 계속 써도 괜찮다.

 

🍬next.js 프로젝트 설치

폴더를 만든 뒤, npm init -y 를 통해 package.json파일을 하나 만들어준다.

이후 아래와 같이 터미널에 관련 파일을 설치해준다. react, next, react-dom을 모두 설치했다.

이 과정에서 시작부터 험난하게 맞닥뜨린…

지난 node 중복설치로 노드 버전이 꼬이며 npm이 아예 안 먹히던 에러 해결은 여기로. 

https://hj97codeart.tistory.com/143

npm i react@latest next@latest react-dom@latest

이제, packjson의 script 부분에서 dev를 하단처럼 수정해준다.

dev 명령어로 npm run dev을 실행 시, 이제 NextJS가 실행될 것이다.

  "scripts": {
    "dev": "next dev"
  },

이제 app이라는 폴더 내부에 page라는 파일을 기본으로 하나 만든다. 여기서 이 이름을 꼭 지켜줘야 함!(규칙)

next js는 실행될 때 반드시 이 파일을 찾으려고 할 것이다. 나는 타입 스크립트를 쓸 것이기에 page.tsx 파일로 만들었다.

export default function Tomato(){
    return <h1>안녕하세요. 처음 next JS를 시작했어요.</h1>
}

파일 내부에 들어가는 내용은 일단 무엇이든 상관없다. npm run dev을 하면, next js가 알아서 타입스크립트를 먼저 설치해야 한다고 설명한 뒤 깔아준다. 정말 멋진 기능이 아닐 수 없다.

다시 npm run dev을 하자 localhost:3000에서 원활히 실행되는 것을 확인 가능하다!! 🤩

심지어 세이브 때마다 자동으로 수정 사항도 바로 반영해준다.

그런데 root 레이아웃이 없다고 하단과 같은 메세지가 나오는데, 이에 관련된 부분은 차차 알아가보기로 하자.

 ⚠ Your page app/page.tsx did not have a root layout. We created app/layout.tsx for you.

⇒ 삭제해도 필요하다고 생각한 next js쪽에서 알아서 layout.tsx를 생성해준다!!


🚩Routing

react-router은 프레임워크 없이 기존에 리액트에서 라우터를 쓰는 방법이었다.

그러나 next js에서는 직접 수동으로 연결해줄 필요가 없으며, 파일 구조만으로 페이지를 생성해줄 수 있다.

우선 원하는 router의 이름으로 app폴더 내부에 폴더를 생성해주고, 그 내부에 또다른 page.tsx 파일을 만든다.

이제 해당 페이지에서 보여주고 싶은 내용을 리턴해준다.

// about-us/page.tsx
export default function AboutUs(){
    return <h1>리턴 됩니다.</h1>
}

/about-us 주소로 가보면 해당 컴포넌트가 보이는 것을 확인할 수 있다! 이처럼 nextJS에서는 편하게 라우터 사용 가능하다.

이를 위해서는 꼭 원하는 페이지마다 ‘page’라는 이름의 파일이 필요함을 기억할 것.

✨중요!: Next.js에서 직접적인 page.tsx 파일이 없는 폴더는, 실제 페이지 없이 경로의 일부분에 속한다.

✨app 폴더 내부에 page말고 다른 파일을 넣어도 될까?

→넣어도 된다.(원한다면… 추천x) 그러나 어차피 해당 요소는 페이지가 되지는 못한다!

🍬not-found

next JS에서 존재하지 않는 페이지는 not-found라는 이름의 파일을 app폴더 내부에 만들어주어 해결할 수 있다.

이름이 중요하다. (함수 이름은 상관X)

그러면 해당 폴더의 내용이 존재하지 않는 url의 페이지마다 보여진다.

export default function NotFound(){
    return <h1>not!!! found!!!</h1>
}


🍬네비게이션 보여주기(feat: “use client”)

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>
    )
    }

그렇다면, 여러 페이지의 상단에 공통적으로 보여지는 네비게이션 파트를 제작해보자.

next.js에서는 a태그가 아니라 Link 태그를 사용해서 이동한다.

이렇게 완성한 네비게이션에서, 유저가 어디에 위치해있는지 보여주고 싶다면 훅 중에서도 usePathname을 사용해보자.

    const path= usePathname();
    console.log(path)

그런데 console.log를 찍어봤더니… 두둥.

아래와 같은 에러를 맞닥뜨리게 된다. 내용을 천천히 읽어보자면 usePathname은 클라이언트 컴포넌트 내부에서만 작동하며, 만약 사용하고 싶다면 “use client”를 상단에 적어달라고 요구하고 있다.

⨯ node_modules/next/dist/client/components/client-hook-in-server-component-error.js (17:18) @ clientHookInServerComponentError
⨯ Error: usePathname only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: <https://nextjs.org/docs/messages/react-client-hook-in-server-component>
    at Navigation (./components/navigation.tsx:13:78)
    at stringify ()
digest: "2075530235"
null

“”를 빼먹으면 곤란하다.

상단에 적어주고 나면, 원하는대로 페이지가 보여진다.

이제 path를 본격적으로 활용해보자.

<nav>
        <ul>
            <li><Link href="/">Home</Link> {path==="/"?"🥰":""}</li>
            <li><Link href="/about-us">About us</Link>{path==="/about-us"?"🥰":""}</li>
        </ul>
</nav>

삼항연산자를 사용해서 사용자가 현재 위치한 path에 따라 이모티콘이 붙을 수 있도록 처리했다.

Navigation은 about-us의 컴포넌트 내부에도 import 시켜 그 페이지에서도 해당 네비게이션이 보이도록 하였다.

어느 페이지로 가든, 이모티콘이 자신이 위치한 url에 맞게 나오는 것을 볼 수 있다.

import Navigation from "../../components/navigation"
export default function AboutUs(){
    return <> <Navigation/></>
}
//about-us페이지에도 동일한 네비게이션을 보여준다.


🍬 CSR & SSR

순수하게 React를 사용해서 만든 프로젝트의 경우 CSR을 사용한다. 따라서 모든 것이 client side rendering으로 이루어진다. 즉, client 측 사용자의 브라우저 단에서 UI를 구축해주어야 한다.

CSR 방식은 작동 방식 때문에 2가지 단점이 있는데,

  1. 페이지의 실제 소스코드가 빈 html인 채로 보여진다. 브라우저가 다운로드한 Javascript에 의해 빈 html 안에 코드들이 추가되기 때문에, 자바스크립트가 다운받고 보여주는 간극(깜박이 현상)이 존재한다. 따라서 브라우저에서 JS를 비활성화 시켜뒀을시, UI상 보이는 것이 아무것도 없다. 사용자가 좋지 않은 인터넷 환경에 있을 시, JS를 전부 다운로드하기까지 흰 스크린을 계속 보게 된다.
  2. 페이지가 비어 있기 때문에, 당연히 SEO에 불리하다!

⇒ 그러나 React와 달리, next.js는 자동으로 default SSR이다.

  1. 따라서 브라우저가 HTML을 보여주기까지 JS가 필요없다. 유저가 페이지에 입장하면, next js는 서버 측에서 앱을 render해준다. 이렇게 제작된 html을 사용자에게 response로 보여준다. 따라서 처음 ‘빈 html’이 존재하지 않는다. 브라우저는 즉시 화면에 표시할 수 있다.
  2. 넘겨받는 것이 빈 html이 아니기 때문에, SEO에도 유리해진다.
  • use client?
    • next.js의 *“use client”*를 사용해도, 클라이언트 단에서만 render되는 것이 절대 아니다.(착오 금지!!!)
    • use client에 상관없이, next js의 모든 컴포넌트들은 먼저 backend에서 render된다. 즉 html로 변환되어 브라우저에게 넘겨진다.

🍬 리액트와 hydration, 그리고 “use client”의 필요성

hydration은 단순한 HTML을 리액트 Application으로 초기화해주는 작업을 말한다.

처음 브라우저는 SSR로 완성된, 상호작용이 불가능하고 지루한 html 파일을 받아온다. 유저는 처음 들어올 때 이 html을 보지만, 이때 뒤에서 빠르게 next.js를 로딩하고 framework를 초기화하며, 초기 html 위에 React 애플리케이션을 활성화시키는 것이다.

→ 건조하게 말라있는 html에 새 생명을 불어넣는 과정에 대한 비유라고 보면 됨!

→ 만약 유저가 아주 느린 인터넷 환경에 있다면 Link 기능이 활성화되기 전까지 html의 a태그로만 이동하게 될 것이다.

⇒ BUT! 이 hydration이 모든 컴포넌트에 발생하지는 않는다.

hydration가 발생하는 컴포넌트는 오직 “use client” 지시어가 맨 위에 적힌 컴포넌트 뿐이다.

즉, “이 컴포넌트는 client 에서 상호작용이 가능해야 해!”라고 미리 말해주는 것이라고 보면 된다.

컴포넌트를 만들다가 에러를 만나면 그때 use client를 추가해주면 된다.

걱정할 것 없고 아주 쉽다🥰

⇒ use client라고 적혀있지 않은 컴포넌트들은 모두 server component가 된다. 이 컴포넌트들은 유저와 상호작용이 필요 없기에 JS도 받을 필요가 없는 것이다. 사용자 입장에서는 쓸데없는 JS 코드를 적게 다운받으면 되니 오히려 좋다!!

⇒ 또한 서버 컴포넌트인 곳에서는 JS가 브라우저에게 전달되지 않기 때문에, 안심하고 DB와 통신하거나 API키를 사용해도 된다.

기존까지는 next js의 모든 컴포넌트가 hydrate되었는데, use client 덕분에 그럴 필요가 없어졌다.

단, 사용상 주의할 것: 클라이언트 컴포넌트를 서버 컴포넌트 안에 넣는 것만 가능. 아직 그 역은 불가능하다.


🍬 layout

layout은 재사용되는 요소들을 위한 파일이다.

아래와 같이 먼저 Layout 부분을 렌더링하고, 내부에 자신이 보고 싶은 페이지의 내용이 children으로 들어온다.

<Layout>
	<Component/>
	//{children}
</Layout>

이것을 응용해서, 미리 제작했던 상단부 Navigation 부분을 최상단 Rootlayout에 넣어 모든 페이지에서 공유되게 하였다.

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <Navigation/>
        {children}
      </body>
    </html>
  )
}

또한 자신이 원하는 폴더에서 해당 폴더 내에 공통적으로 사용될 layout 파일을 추가로 만들 수도 있다.

layout은 여러 개가 생기면 서로를 상쇄하는 것이 아니라, 각 폴더마다 layout가 있으면 여러 개 중첩이 가능하다.

상위 요소가 갖고 있는 layout이 해당 폴더의 하부 파일들에 전부 렌더링된다.

아쉬운 점: page와 layout이 많아지면 간혹 어떤 파일인지 헷갈리는 경우가 발생할 수 있다!그렇다면, 여러 페이지의 상단에 공통적으로 보여지는 네비게이션 파트를 제작해보자.

next.js에서는 a태그가 아니라 Link 태그를 사용해서 이동한다.

이렇게 완성한 네비게이션에서, 유저가 어디에 위치해있는지 보여주고 싶다면 훅 중에서도 usePathname을 사용해보자.

    const path= usePathname();
    console.log(path)

그런데 console.log를 찍어봤더니… 두둥.

아래와 같은 에러를 맞닥뜨리게 된다. 내용을 천천히 읽어보자면 usePathname은 클라이언트 컴포넌트 내부에서만 작동하며, 만약 사용하고 싶다면 “use client”를 상단에 적어달라고 요구하고 있다.

⨯ node_modules/next/dist/client/components/client-hook-in-server-component-error.js (17:18) @ clientHookInServerComponentError
⨯ Error: usePathname only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: <https://nextjs.org/docs/messages/react-client-hook-in-server-component>
    at Navigation (./components/navigation.tsx:13:78)
    at stringify ()
digest: "2075530235"
null

“”를 빼먹으면 곤란하다.

상단에 적어주고 나면, 원하는대로 페이지가 보여진다.

이제 path를 본격적으로 활용해보자.

<nav>
        <ul>
            <li><Link href="/">Home</Link> {path==="/"?"🥰":""}</li>
            <li><Link href="/about-us">About us</Link>{path==="/about-us"?"🥰":""}</li>
        </ul>
</nav>

삼항연산자를 사용해서 사용자가 현재 위치한 path에 따라 이모티콘이 붙을 수 있도록 처리했다.

Navigation은 about-us의 컴포넌트 내부에도 import 시켜 그 페이지에서도 해당 네비게이션이 보이도록 하였다.

어느 페이지로 가든, 이모티콘이 자신이 위치한 url에 맞게 나오는 것을 볼 수 있다.

import Navigation from "../../components/navigation"
export default function AboutUs(){
    return <> <Navigation/></>
}
//about-us페이지에도 동일한 네비게이션을 보여준다.

🍬 CSR & SSR

순수하게 React를 사용해서 만든 프로젝트의 경우 CSR을 사용한다. 따라서 모든 것이 client side rendering으로 이루어진다.

즉, client 측 사용자의 브라우저 단에서 UI를 구축해주어야 한다.

CSR 방식은 작동 방식 때문에 2가지 단점이 있는데,

  1. 페이지의 실제 소스코드가 빈 html인 채로 보여진다. 브라우저가 다운로드한 Javascript에 의해 빈 html 안에 코드들이 추가되기 때문에, 자바스크립트가 다운받고 보여주는 **간극(깜박이)**이 존재한다. 따라서 브라우저에서 JS를 비활성화 시켜뒀을시, UI상 보이는 것이 아무것도 없다. 사용자가 좋지 않은 인터넷 환경에 있을 시, JS를 전부 다운로드하기까지 흰 스크린을 계속 보게 된다.
  2. 페이지가 비어 있기 때문에, 당연히 SEO에 불리하다!

⇒ 그러나 React와 달리, next.js는 자동으로 default SSR이다.

  1. 따라서 브라우저가 HTML을 보여주기까지 JS가 필요없다. 유저가 페이지에 입장하면, next js는 서버 측에서 앱을 render해준다. 이렇게 제작된 html을 사용자에게 response로 보여준다. 따라서 처음 ‘빈 html’이 존재하지 않는다. 브라우저는 즉시 화면에 표시할 수 있다.
  2. 넘겨받는 것이 빈 html이 아니기 때문에, SEO에도 유리해진다.
  • use client?
    • next.js의 *“use client”*를 사용해도, 클라이언트 단에서만 render되는 것이 절대 아니다.(착오 금지!!!)
    • use client에 상관없이, next js의 모든 컴포넌트들은 먼저 backend에서 render된다. 즉 html로 변환되어 브라우저에게 넘겨진다.

🍬 리액트와 hydration, 그리고 “use client”의 필요성

hydration은 단순한 HTML을 리액트 Application으로 초기화해주는 작업을 말한다.

처음 브라우저는 SSR로 완성된, 상호작용이 불가능하고 지루한 html 파일을 받아온다. 유저는 처음 들어올 때 이 html을 보지만, 이때 뒤에서 빠르게 next.js를 로딩하고 framework를 초기화하며, 초기 html 위에 React 애플리케이션을 활성화시키는 것이다.

→ 건조하게 말라있는 html에 새 생명을 불어넣는 과정에 대한 비유라고 보면 됨!

→ 만약 유저가 아주 느린 인터넷 환경에 있다면 Link 기능이 활성화되기 전까지 html의 a태그로만 이동하게 될 것이다.

⇒ BUT! 이 hydration이 모든 컴포넌트에 발생하지는 않는다.

hydration가 발생하는 컴포넌트는 오직 “use client” 지시어가 맨 위에 적힌 컴포넌트 뿐이다.

즉, “이 컴포넌트는 client 에서 상호작용이 가능해야 해!”라고 미리 말해주는 것이라고 보면 된다.

컴포넌트를 만들다가 에러를 만나면 그때 use client를 추가해주면 된다.

걱정할 것 없고 아주 쉽다🥰

⇒ use client라고 적혀있지 않은 컴포넌트들은 모두 server component가 된다. 이 컴포넌트들은 유저와 상호작용이 필요 없기에 JS도 받을 필요가 없는 것이다. 사용자 입장에서는 쓸데없는 JS 코드를 적게 다운받으면 되니 오히려 좋다!!

⇒ 또한 서버 컴포넌트인 곳에서는 JS가 브라우저에게 전달되지 않기 때문에, 안심하고 DB와 통신하거나 API키를 사용해도 된다.

기존까지는 next js의 모든 컴포넌트가 hydrate되었는데, use client 덕분에 그럴 필요가 없어졌다.

단, 사용상 주의할 것: 클라이언트 컴포넌트를 서버 컴포넌트 안에 넣는 것만 가능. 아직 그 역은 불가능하다.


🍬 layout

layout은 재사용되는 요소들을 위한 파일이다.

아래와 같이 먼저 Layout 부분을 렌더링하고, 내부에 자신이 보고 싶은 페이지의 내용이 children으로 들어온다.

<Layout>
	<Component/>
	//{children}
</Layout>

이것을 응용해서, 미리 제작했던 상단부 Navigation 부분을 최상단 Rootlayout에 넣어 모든 페이지에서 공유되게 하였다.

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <Navigation/>
        {children}
      </body>
    </html>
  )
}

또한 자신이 원하는 폴더에서 해당 폴더 내에 공통적으로 사용될 layout 파일을 추가로 만들 수도 있다.

layout은 여러 개가 생기면 서로를 상쇄하는 것이 아니라, 각 폴더마다 layout가 있으면 여러 개 중첩이 가능하다.

상위 요소가 갖고 있는 layout이 해당 폴더의 하부 파일들에 전부 렌더링된다.

아쉬운 점: page와 layout이 많아지면 간혹 어떤 파일인지 헷갈리는 경우가 발생할 수 있다!

🚩Introduce

Next.js는 풀스택 웹 앱을 개발하기에 있어, 최고의 프레임워크라고 해도 과언이 아니다.

리액트 프레임워크 중에서는 next.js가 현재 1위를 차지했다.

🍬React(라이브러리) vs next.js(프레임워크) ?

라이브러리: 내가 원하는 방식으로 사용한다. 코드 내에서 ‘우리’가 필요할 때 결정해서 내가 주체적으로 사용하는 원리이다.

프레임워크: 나에게 상대적으로 주도권이 없다. 다만 개발자가 기존까지 일일이 내려야하는 결정들을 자동화하여 훨씬 쉽게 구현할 수 있게 도와준다. 따라서 우리는 미리 정해진 ‘규칙’들을 지켜야 한다.

→ next.js는 리액트와 달리, 이러한 규칙이 존재하는 프레임워크다. 따라서 next.js를 사용하기 위해서는 이런 규칙들을 배워야 한다!

?당신이 만약 next js 구버전을 쓰고 있다면…..

→ Next.js 14부터 기존 버전과 다르게 새롭게 들어온 기능들이 있다. 특히 app router은 기존의 pages router과 많이 달라졌다. 하지만 당장 전부 마이그레이션 하지 않고 기존의 pages router을 계속 써도 괜찮다.

🍬next.js 프로젝트 설치

폴더를 만든 뒤, npm init -y 를 통해 package.json파일을 하나 만들어준다.

이후 아래와 같이 터미널에 관련 파일을 설치해준다. react, next, react-dom을 모두 설치했다.

이 과정에서 시작부터 험난하게 맞닥뜨린… 지난 node 중복설치로 노드 버전이 꼬이며 npm이 아예 안 먹히던 에러 해결은 여기로

https://hj97codeart.tistory.com/143

npm i react@latest next@latest react-dom@latest

이제, packjson의 script 부분에서 dev를 하단처럼 수정해준다.

dev 명령어로 npm run dev을 실행 시, 이제 NextJS가 실행될 것이다.

  "scripts": {
    "dev": "next dev"
  },

이제 app이라는 폴더 내부에 page라는 파일을 기본으로 하나 만든다. 여기서 이 이름을 꼭 지켜줘야 함!(규칙)

next js는 실행될 때 반드시 이 파일을 찾으려고 할 것이다. 나는 타입 스크립트를 쓸 것이기에 page.tsx 파일로 만들었다.

export default function Tomato(){
    return <h1>안녕하세요. 처음 next JS를 시작했어요.</h1>
}

파일 내부에 들어가는 내용은 일단 무엇이든 상관없다. npm run dev을 하면, next js가 알아서 타입스크립트를 먼저 설치해야 한다고 설명한 뒤 깔아준다. 정말 멋진 기능이 아닐 수 없다.

다시 npm run dev을 하자 localhost:3000에서 원활히 실행되는 것을 확인 가능하다!! 🤩

심지어 세이브 때마다 자동으로 수정 사항도 바로 반영해준다.

그런데 root 레이아웃이 없다고 하단과 같은 메세지가 나오는데, 이에 관련된 부분은 차차 알아가보기로 하자.

 ⚠ Your page app/page.tsx did not have a root layout. We created app/layout.tsx for you.

⇒ 삭제해도 필요하다고 생각한 next js쪽에서 알아서 layout.tsx를 생성해준다!!


🚩Routing

react-router은 프레임워크 없이 기존에 리액트에서 라우터를 쓰는 방법이었다.

그러나 next js에서는 직접 수동으로 연결해줄 필요가 없으며, 파일 구조만으로 페이지를 생성해줄 수 있다.

우선 원하는 router의 이름으로 app폴더 내부에 폴더를 생성해주고, 그 내부에 또다른 page.tsx 파일을 만든다.

이제 해당 페이지에서 보여주고 싶은 내용을 리턴해준다.

// about-us/page.tsx
export default function AboutUs(){
    return <h1>리턴 됩니다.</h1>
}

/about-us 주소로 가보면 해당 컴포넌트가 보이는 것을 확인할 수 있다! 이처럼 nextJS에서는 편하게 라우터 사용 가능하다.

이를 위해서는 꼭 원하는 페이지마다 ‘page’라는 이름의 파일이 필요함을 기억할 것.

✨중요!: Next.js에서 직접적인 page.tsx 파일이 없는 폴더는, 실제 페이지 없이 경로의 일부분에 속한다.

✨app 폴더 내부에 page말고 다른 파일을 넣어도 될까?

→넣어도 된다.(원한다면… 추천x) 그러나 어차피 해당 요소는 페이지가 되지는 못한다!

🍬not-found

next JS에서 존재하지 않는 페이지는 not-found라는 이름의 파일을 app폴더 내부에 만들어주어 해결할 수 있다.

이름이 중요하다. (함수 이름은 상관X)

그러면 해당 폴더의 내용이 존재하지 않는 url의 페이지마다 보여진다.

export default function NotFound(){
    return <h1>not!!! found!!!</h1>
}

🍬네비게이션 보여주기(feat: “use client”)

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>
    )
    }

그렇다면, 여러 페이지의 상단에 공통적으로 보여지는 네비게이션 파트를 제작해보자.

next.js에서는 a태그가 아니라 Link 태그를 사용해서 이동한다.

이렇게 완성한 네비게이션에서, 유저가 어디에 위치해있는지 보여주고 싶다면 훅 중에서도 usePathname을 사용해보자.

    const path= usePathname();
    console.log(path)

그런데 console.log를 찍어봤더니… 두둥.

아래와 같은 에러를 맞닥뜨리게 된다. 내용을 천천히 읽어보자면 usePathname은 클라이언트 컴포넌트 내부에서만 작동하며, 만약 사용하고 싶다면 “use client”를 상단에 적어달라고 요구하고 있다.

⨯ node_modules/next/dist/client/components/client-hook-in-server-component-error.js (17:18) @ clientHookInServerComponentError
⨯ Error: usePathname only works in Client Components. Add the "use client" directive at the top of the file to use it. Read more: <https://nextjs.org/docs/messages/react-client-hook-in-server-component>
    at Navigation (./components/navigation.tsx:13:78)
    at stringify ()
digest: "2075530235"
null

“”를 빼먹으면 곤란하다.

 

상단에 적어주고 나면, 원하는대로 페이지가 보여진다.

이제 path를 본격적으로 활용해보자.

<nav>
        <ul>
            <li><Link href="/">Home</Link> {path==="/"?"🥰":""}</li>
            <li><Link href="/about-us">About us</Link>{path==="/about-us"?"🥰":""}</li>
        </ul>
</nav>

삼항연산자를 사용해서 사용자가 현재 위치한 path에 따라 이모티콘이 붙을 수 있도록 처리했다.

Navigation은 about-us의 컴포넌트 내부에도 import 시켜 그 페이지에서도 해당 네비게이션이 보이도록 하였다.

어느 페이지로 가든, 이모티콘이 자신이 위치한 url에 맞게 나오는 것을 볼 수 있다.

import Navigation from "../../components/navigation"
export default function AboutUs(){
    return <> <Navigation/></>
}
//about-us페이지에도 동일한 네비게이션을 보여준다.

🍬 CSR & SSR

순수하게 React를 사용해서 만든 프로젝트의 경우 CSR을 사용한다. 따라서 모든 것이 client side rendering으로 이루어진다.

즉, client 측 사용자의 브라우저 단에서 UI를 구축해주어야 한다.

CSR 방식은 작동 방식 때문에 2가지 단점이 있는데,

  1. 페이지의 실제 소스코드가 빈 html인 채로 보여진다. 브라우저가 다운로드한 Javascript에 의해 빈 html 안에 코드들이 추가되기 때문에, 자바스크립트가 다운받고 보여주는 **간극(깜박이)**이 존재한다. 따라서 브라우저에서 JS를 비활성화 시켜뒀을시, UI상 보이는 것이 아무것도 없다. 사용자가 좋지 않은 인터넷 환경에 있을 시, JS를 전부 다운로드하기까지 흰 스크린을 계속 보게 된다.
  2. 페이지가 비어 있기 때문에, 당연히 SEO에 불리하다!

⇒ 그러나 React와 달리, next.js는 자동으로 default SSR이다.

  1. 따라서 브라우저가 HTML을 보여주기까지 JS가 필요없다. 유저가 페이지에 입장하면, next js는 서버 측에서 앱을 render해준다. 이렇게 제작된 html을 사용자에게 response로 보여준다. 따라서 처음 ‘빈 html’이 존재하지 않는다. 브라우저는 즉시 화면에 표시할 수 있다.
  2. 넘겨받는 것이 빈 html이 아니기 때문에, SEO에도 유리해진다.
  • use client?
    • next.js의 “use client”를 사용해도, 클라이언트 단에서만 render되는 것이 절대 아니다.(착오 금지!!!)
    • use client에 상관없이, next js의 모든 컴포넌트들은 먼저 backend에서 render된다. 즉 html로 변환되어 브라우저에게 넘겨진다.

🍬 리액트와 hydration, 그리고 “use client”의 필요성

hydration은 단순한 HTML을 리액트 Application으로 초기화해주는 작업을 말한다.

처음 브라우저는 SSR로 완성된, 상호작용이 불가능하고 지루한 html 파일을 받아온다. 유저는 처음 들어올 때 이 html을 보지만, 이때 뒤에서 빠르게 next.js를 로딩하고 framework를 초기화하며, 초기 html 위에 React 애플리케이션을 활성화시키는 것이다.

→ 건조하게 말라있는 html에 새 생명을 불어넣는 과정에 대한 비유라고 보면 됨!

→ 만약 유저가 아주 느린 인터넷 환경에 있다면 Link 기능이 활성화되기 전까지 html의 a태그로만 이동하게 될 것이다.

⇒ BUT! 이 hydration이 모든 컴포넌트에 발생하지는 않는다.

hydration가 발생하는 컴포넌트는 오직 “use client” 지시어가 맨 위에 적힌 컴포넌트 뿐이다.

즉, “이 컴포넌트는 client 에서 상호작용이 가능해야 해!”라고 미리 말해주는 것이라고 보면 된다.

컴포넌트를 만들다가 에러를 만나면 그때 use client를 추가해주면 된다.

걱정할 것 없고 아주 쉽다🥰

⇒ use client라고 적혀있지 않은 컴포넌트들은 모두 server component가 된다. 이 컴포넌트들은 유저와 상호작용이 필요 없기에 JS도 받을 필요가 없는 것이다. 사용자 입장에서는 쓸데없는 JS 코드를 적게 다운받으면 되니 오히려 좋다!!

⇒ 또한 서버 컴포넌트인 곳에서는 JS가 브라우저에게 전달되지 않기 때문에, 안심하고 DB와 통신하거나 API키를 사용해도 된다.

기존까지는 next js의 모든 컴포넌트가 hydrate되었는데, use client 덕분에 그럴 필요가 없어졌다.

단, 사용상 주의할 것: 클라이언트 컴포넌트를 서버 컴포넌트 안에 넣는 것만 가능. 아직 그 역은 불가능하다.


🍬 layout

layout은 재사용되는 요소들을 위한 파일이다.

아래와 같이 먼저 Layout 부분을 렌더링하고, 내부에 자신이 보고 싶은 페이지의 내용이 children으로 들어온다.

<Layout>
	<Component/>
	//{children}
</Layout>

이것을 응용해서, 미리 제작했던 상단부 Navigation 부분을 최상단 Rootlayout에 넣어 모든 페이지에서 공유되게 하였다.

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <Navigation/>
        {children}
      </body>
    </html>
  )
}

또한 자신이 원하는 폴더에서 해당 폴더 내에 공통적으로 사용될 layout 파일을 추가로 만들 수도 있다.

layout은 여러 개가 생기면 서로를 상쇄하는 것이 아니라, 각 폴더마다 layout가 있으면 여러 개 중첩이 가능하다.

상위 요소가 갖고 있는 layout이 해당 폴더의 하부 파일들에 전부 렌더링된다.

아쉬운 점: page와 layout이 많아지면 간혹 어떤 파일인지 헷갈리는 경우가 발생할 수 있다!