[Next.js] Next.js 시작하기 - (1)

zzzzsb·2023년 1월 12일
0

노마드코더 - Next.js 시작하기 강의를 참고로 하여 정리했다.
강의와는 달리 next.js 13버전 + 타입스크립트로 작성하며 공부했다.
(버전 차이, 타입스크립트 코드 등 강의 내용과 다른 부분은 추가적으로 공식문서를 참고해 코드 변경함)

Next.js

https://nextjs.org/

프로젝트 생성

npx create-next-app@latest
npx create-next-app@latest --typescript

프로젝트 명 입력해주고 설치 기다리면..

위와같이 프로젝트 생성 완료!
vscode에서 해당 폴더를 열어보자

폴더 구조

실행

npm run dev 


1.0 프레임워크 vs 라이브러리

라이브러리

  • 개발자는 라이브러리를 불러와서 사용한다.
  • 개발자는 원하는대로 코드를 작성할 수 있다.
  • 개발자는 사용하고 싶을때 라이브러리를 사용하면 된다.
  • 폴더 구조, 언제 어떤 파일을 불러올지 등은 개발자가 결정한다.
  • 자유도가 높음

ex) react는 개발자가 원하는대로 폴더구조 세팅하고, 코드 작성할 수 있음.

프레임워크

  • 프레임워크가 개발자의 코드를 불러온다.
  • 특정한 규칙을 따라야 한다.
  • 개발자가 적절한 위치에 코드를 작성하면, 프레임워크는 그 코드를 불러와서 사용한다.
  • 자유도가 낮음

ex) 다 지어져있는 집, 개발자와 코드는 게스트와 같은 존재

ex) next.js는 특정 규칙을 따라야 정상동작함. ReactDOM.render 없음. -> Pages 내에서 무언가 만드는 것만 할 수 있다.

next.js 예시

1) pages/index.tsx

export default function Home() {
  return "hi";
}

http://localhost:3000로 접속해보면, 어떤 설정이나 router 설정 없이도 자동적으로 hi를 확인할 수 있음.

2) pages/about.tsx

about.ts 만들고 안에 코드 작성하면, /about 으로 이동하면 작성한 내용 확인할 수 있음.

export default function Home() {
  return "about";
}

http://localhost:3000/about로 접속하면, about을 확인할 수 있음.


1.1 Pages

react 컴포넌트를 export하는 파일들을 pages 폴더 안에 넣어주면, 파일 이름으로 url을 만들어 자동으로 라우팅 해준다.

특징

  • 파일 이름이 url이 됨.

  • export default function ~ 형태로 컴포넌트 작성해야함.

  • 404 페이지도 자동으로 만들어져 있음.(커스터마이징 가능)

  • index.ts는 예외적으로 홈페이지로 연결됨.(앱의 Home, url 그냥 /)

  • import react from "react"; 할 필요 없음!


1.2 Static Pre Rendering

  • next.js는 앱의 페이지들이 미리 정적으로 렌더링 됨.

SPA(React, CSR)

  • CSR(Client-Side Rendering)

  • CRA(create-react-app)로 생성한 프로젝트는 모두 클라이언트 사이드 렌더링이다.

  • 브라우저가 자바스크립트 코드 가져와서 모든 UI를 빌드해서 보여줌.(유저가 볼 수 있는 상태)

  • 사용자는 처음에 비어있는 HTML을 보게됨. 이후 브라우저가 JS 파일 로드-실행해서 화면을 그려줌.
    - 만약 브라우저에서 자바스크립트를 비활성화 했을때, noscript 태그가 있었다면 <noscript>자바스크립트가 활성화 되지 않았습니다.</noscript>라고 보여질것.

  • 브라우저가 JS 파일을 통해 UI를 그려내는 작업은 비용이 크고 오래걸리는 작업이다.
    - Networt 탭에서 Slow 3G 연결로 설정하고 새로고침하면 사용자는 처음에 빈 화면 보게됨, 시간이 지나야 페이지 출력됨

Static Pre Rendering

  • next.js에서는 프론트에서 react.js를 실행해 html을 완성한 후 보냄(페이지가 pre-rendering 되어 전달됨)
  • next.js 페이지 소스코드에는 실제 HTML 코드가 있음.
  • 유저의 네트워크가 매우 느리거나, 자바스크립트가 비활성화 되더라도 유저는 어떠한 HTML은 볼수 있음!(빠른 로딩 가능)

Hydration

  • Server Side 단에서 Pre-Rendering된 HTML 페이지와 번들링된 JS파일을 클라이언트에게 보낸 뒤, 클라이언트 단에서 HTML 코드와 React인 JS코드를 서로 매칭 시키는 과정

  • 자바스크립트 코드들이 DOM 요소 위에 물을 채우듯 필요로 하던 요소들을 채운다 하여 Hydrate(수화)라는 용어를 쓴다고 한다.

  • 브라우저가 자바스크립트를 비활성화하면 초기 html은 그려져 있지만, 동적으로 동작하지는 않음

예제 - pages/index.tsx

import { useState } from "react";

export default function Home() {
  const [counter, setCounter] = useState(0);
  return (
    <div>
      <h1>Hello {counter}</h1>
      <button onClick={() => setCounter((prev) => prev + 1)}>+</button>
    </div>
  );
}

  • 작성한 HTML 코드들이 초기에 존재하는 것을 확인할 수 있음.

  • next.js는 react.js를 백엔드에서 동작시켜 첫 페이지를 미리 렌더링함. -> HTML (초기 상태 pre-rendering)

  • 유저는 js코드가 존재하지 않아도 HTML 볼 수 있음. 이후 js코드가 로딩되었을때, 일반적으로 동작하는 react 앱이 되는 것!

  • 유저는 웹사이트 접속했을때 미리 생성된 초기 HTML 페이지를 먼저 보게된다.

  • 자바스크립트 비활성화 하면 코드 동작하지 않음, 하지만 유저가 무엇인가는 볼수 있게 됨!
    (사용자가 빈페이지 보는것 보다는 훨씬 낫다!)

  • SEO에 매우 좋음


1.3 Routing

보통 페이지간 이동은 a 태그를 사용하지만, next.js에서는 사용하지 않는다.

a 태그를 사용하면 처음 페이지 진입시 번들파일을 받고, a태그에 의해 라우팅 되면서 다시 번들파일을 받기 때문이다. 또 redux를 사용하는 경우에는 store의 state 값이 증발되는 현상도 발생한다 한다.

그렇기 때문에 next에서 페이지간 이동에는 모두 Link 태그를 사용한다.

<Link href="/">
	<a>Home</a>
</Link>

노마드코더 강의에서는 <Link> 태그 안에 자식태그로 <a>를 넣어 위와 같이 사용했는데, 아래와 같은 에러가 떴다.

Invalid <Link> with <a> child
https://nextjs.org/docs/messages/invalid-new-link-with-extra-anchor

Starting with Next.js 13, <Link> renders as <a>, so attempting to use <a> as a child is invalid.

next.js 13 버전에서는 더이상 a 태그를 자식으로 포함하지 않아도 된다.(기본으로 포함)

components/NavBar.tsx

import Link from "next/link";
import { useRouter } from "next/router";

export default function NavBar() {
  const router = useRouter();
  console.log(router);
  return (
    <nav>
      <Link
        href="/"
        style={{ color: router.pathname === "/" ? "red" : "blue" }}
      >
        Home
      </Link>
      <Link
        href="/about"
        style={{ color: router.pathname === "/about" ? "red" : "blue" }}
      >
        About
      </Link>
    </nav>
  );
}

useRouter

  • next.js에 있는 Hook
  • location 정보를 얻을 수 있고, pathname으로 현재 url을 알 수 있다.

pages/index.tsx

import NavBar from "../components/NavBar";

export default function Home() {
  return (
    <div>
      <NavBar />
      <h1>Hello</h1>
    </div>
  );
}

pages/about.tsx

import NavBar from "../components/NavBar";

export default function Home() {
  return (
    <div>
      <NavBar />
      <h1>About</h1>
    </div>
  );
}

  • 웹사이트 새로고침할 필요 없이 페이지 이동(CSR)
  • NavBar 컴포넌트 내에서 라우팅이 이루어짐!

1.4 CSS Modules

next.js 앱에 css 추가하는 방법은 여러가지가 있음.

.nav {
  display: flex;
  justify-content: space-between;
  background-color: skyblue;
}
import styles from "./NavBar.module.css";

<nav className={styles.nav}>
</nav>

styles.nav 와 같이 클래스 이름을 프로퍼티 형식으로 작성해 사용한다.

  • 실제 브라우저에서 클래스 이름 확인해보면, nav라고 작성한 클래스 이름이 해쉬값을 더해 무작위로 생성되어 있음.
  • 네이밍 스페이스가 모듈 안으로 한정됨. nav라는 클래스 이름을 언제든지 다른 모듈파일에서도 재사용할 수 있다! 클래스 이름 충돌 X
    (페이지 빌드될떄 Next에서 클래스 이름을 무작위로 바꿔주기 때문)

className에 여러 클래스를 적용하려면?

  • 띄어쓰기를 포함한 문자열로 작성해줘야 한다.
  • `` 사용해서 이어주거나 [ ] 배열로 묶어준뒤 join 해주는 방법 등
.link {
  text-decoration: none;
}
.active {
  color: tomato;
}
...
return (
    <nav>
      <Link
        href="/"
        className={`${styles.link} ${
          router.pathname === "/" ? styles.active : ""
        }`}
      >
        Home
      </Link>
      <Link
        href="/about"
        className={[
          styles.link,
          router.pathname === "/about" ? styles.active : "",
        ].join(" ")}
      >
        About
      </Link>
    </nav>
  );


1.5 Styles JSX(ts기준으로 작성)

Styled jsx는 Next.js 고유의 CSS 사용법.

export default function NavBar() {
  const router = useRouter();
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <style jsx>{`
        nav {
          background-color: tomato;
        }
      `}</style>
    </nav>
  );
}

nav 태그 배경이 토마토색으로 변경된 것을 확인할 수 있다.

클래스 이름을 확인해보면, jsx-{해쉬값} 형태로 클래스 이름이 무작위로 생성되어 있다.
(컴포넌트 단위로 네이밍 스페이스가 지정, 스타일이 컴포넌트 내로 한정됨!)

파일 import도 필요없고, 다른 컴포넌트라면 같은 클래스 이름 사용할 수 있음.

``으로 묶인 문자열이기에, props로 받은 변수도 사용 가능하다. color: ${props.color}

next.js 13 버전에서는 Link 태그를 사용할때 더이상 a태그를 자식으로 포함하지 않아도 된다.

하지만, a태그에 클래스 지정해줘야 하는 상황에서는?
Link태그에 legacyBehavior를 추가해주어야 오류 없이 실행된다.

...
    <nav>
      <Link href="/" legacyBehavior>
        <a className={router.pathname === "/" ? "active" : ""}>Home</a>
      </Link>
      <Link href="/about" legacyBehavior>
        <a className={router.pathname === "/about" ? "active" : ""}>About</a>
      </Link>
      <style jsx>{`
        nav {
          background-color: tomato;
        }
        a {
          text-decoration: none;
        }
        .active {
          color: yellow;
        }
      `}</style>
    </nav>
...

Link태그의 자식에 a태그를 작성해도 오류가 뜨지 않았고, a태그에도 클래스이름이 잘 적용되었다!


1.6 Custom App (_app.tsx)

next.js에서 글로벌 스타일링

  • styled jsx에 global 추가 : <styled jsx global>

하지만 index.tsx 파일에만 global 스타일 적용해주면, about 페이지로 이동했을때는 적용 안되는 문제!

_app.tsx(App 컴포넌트)

  • 가장 먼저 실행되는 컴포넌트
  • pages/_app.tsx 경로에 생성
  • 모든 페이지는 이 컴포넌트를 통해 만들어짐
  • 공통 레이아웃, 글로벌 css 적용에 사용

pages/_app.tsx

import type { AppProps } from "next/app";
import NavBar from "../components/NavBar";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <NavBar />
      <Component {...pageProps} />
      <style jsx global>
        {`
          a {
            color: white;
          }
        `}
      </style>
    </>
  );
}
}

about페이지를 렌더링할때, about 컴포넌트를 App 컴포넌트의 props로({Component, pageProps})로 보내준 다음 합쳐진 것을 그려준다.

지금 예제에서는 NavBar가 어느페이지에서든 보여야하는 공통 컴포넌트 이기에, NavBar를 App 컴포넌트에 넣어주면 된다!
(더이상 index.tsx, about.tsx 모두에<NavBar />넣어줄 필요 없음.)

또한 글로벌 css도 _app.tsx 파일에 작성해주면 된다.

globals.css 파일 import

원래 next.js에서는 예를들어, about.tsx에 globals.css 파일 import 할 수 없음.

하지만, _app.tsx에서는 임포트 가능!

위 에러메시지만 보아도, 글로벌 css는 App 컴포넌트에서 import 하라고 되어있다.

_app.tsx에서 import "../styles/globals.css"; 임포트 해주면 아래와 같이 글로벌 스타일이 적용된다.


1.7 복습

? 라이브러리 vs 프레임워크
? /pages/about.tsx 생성 -> /about으로 라우팅
? /pages/index.tsx -> / 으로 라우팅
? create-next-app vs create-react-app(CSR vs SSR)
? Rehydration
? css modules -> className={styles.nav}
? styled-jsx -> <style jsx> {a { ~~~ }} </style>
? <style jsx global>
? custom App(_app.tsx)

profile
성장하는 developer

0개의 댓글