Next JS 기초

  1. Next JS
    1. 특징
      1. pre-rendering
      2. 라이브러리와 프레임워크의 차이
    2. 사용하기
      1. 프로젝트 생성
      2. 네비게이팅
        1. Link
      3. useRouter
    3. css
      1. className 2개 이상 사용하기
      2. jsx style
      3. jsx global style
    4. Fetching Data
    5. API키 숨기기 (Redirect & Rewrite)
      1. redirects
      2. rewrites
    6. Server Side Rendering
    7. Dynamic Routes
      1. Catch All
    8. 404 에러

Next JS

특징

pre-rendering

  • JS과 React JS가 로딩되지 않아도 콘테츠를 볼 수 있다.

💡 React JS는 먼저 빈 페이지가 나오고 로딩이 끝나야 콘텐츠를 볼 수 있다.

라이브러리와 프레임워크의 차이

라이브러리

  • 내가 원하는 대로 사용

프레임워크

  • 형식에 맞춰 사용

사용하기

프로젝트 생성

npx create-next-app@latest

기본 /pages/about.js

export default function Hello() {
    return "Hello:)";
}

=> 라우터 직접 구성하지 않고 파일명으로 경로를 만들 수 있다.

JSX /pages/about.js

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

네비게이팅

💡 네비게이팅 할 때 <a> anchor 태그를 사용하지 않는 이유 => <a>는 이동하면서 페이지 전체를 새로고침하여 느려질 수 있기 때문이다.

Navgation Bar 생성 /components/NavBar.js

import Link from "next/link";

export default function NavBar() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
    </nav>
  );
}

NavBar 사용하기 /pages/index.js

import Link from "next/link";

export default function NavBar() {
  return (
    <nav>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a style={{ color: "red" }}{{% endraw %}}>About</a>
      </Link>
    </nav>
  );
}

⚠️ Link는 style이나 className을 적용하지 못하기 때문에 안에 <a>를 넣어준다.


useRouter

  • 페이지에 대한 정보를 얻을 수 있다.
import Link from "next/link";
import { useRouter } from "next/router";

export default function NavBar() {
  const router = useRouter();
  return (
    <nav>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a style={% raw %}{{ color: "red" }}>About</a>
      </Link>
    </nav>
  );
}

콘솔 결과

Object { pathname: "/", route: "/", query: {}, asPath: "/", components: {}, isFallback: false, basePath: "", locale: undefined, locales: undefined, defaultLocale: undefined,  }

css

/components/NavBar.module.css

import Link from "next/link";
import { useRouter } from "next/router";
import styles from "./NavBar.module.css";

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

className 2개 이상 사용하기

방법 1. 백틱

<Link href="/">
  <a className={`${styles.link} ${router.pathname === "/" ? styles.active : ""}`}>Home</a>
</Link>

방법 2. join

<Link href="/">
  <a className={[styles.link, router.pathname === "/" ? styles.active : ""].join(" ")}>Home</a>
</Link>

jsx style

<style jsx>{`
        nav {
          display: flex;
          justify-content: space-around;
          background-color: beige;
        }
        a {
          text-decoration: none;
        }
        .active {
          color: red;
          font-size: 24px;
        }
      `}</style>

jsx global style

파일 형식 ex. _app.js

  • 서버 요청이 왔을 때 가장 먼저 실행되는 컴포넌트(공통 레이아웃)

_app.js

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

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

💡Component : 요청한 페이지 💡pageProps : getInitialPros를 통해 내려받은 props


Fetching Data

public 폴더

  • public 폴더에 있으면 따로 경로 설정 없이 바로 불러올 수 있다. ex.
    <img src="vercel.svg">
    

API키 숨기기 (Redirect & Rewrite)

redirects

  • URL에 소스를 입력하면 destination으로 redirect 해준다. next.config.js
    module.exports = {
    reactStrictMode: false,
    async redirect() {
      return [
        {
          source: "/old-blog",
          destination: "/new-blog",
          permanent: false,
        },
      ];
    },
    };
    

    💡premanent :

rewrites

  • 위의 redirects와 동일하나 destination을 보여주지 않는다.(Masking) next.config.js
    module.exports = {
    reactStrictMode: false,
    async rewrite() {
      return [
        {
          source: "/api/movies",
          destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`,
        },
      ];
    },
    };
    

Server Side Rendering

  • loading 화면 없이 모든 처리가 완료될 때까지 기다린 후 모든 정보를 보여주기 위해 사용
  • page를 받아오기 전에 props를 받아오는 function

💡 오직 백엔드에서만 실행된다.

export default function Home({ results }) {
  return (
    <div className="container">
      <Seo title="Home" />
      {results?.map((movie) => (
        <div className="movie" key={movie.id}>
          <img src={`https://image.tmdb.org/t/p/w500/${movie.poster_path}`} />
          <h4>{movie.original_title}</h4>
        </div>
      ))}
    </div>
  );
}

export async function getServerSideProps() {
  const { results } = await (await fetch(`http://localhost:3000/api/movies`)).json();
  return {
    props: {
      results,
    },
  };
}

=> server side를 통해 props를 page로 보낸다.


💡Seo(Search Engine Optimization)

  • 검색 엔진 최적화로 인덱싱하는데 도움을 주는 방식이다.

Dynamic Routes

http://localhost:3000/movies 접속 /pages/movies/index.js //root 페이지

http://localhost:3000/movies/all 접속 /pages/movies/all.js

http://localhost:3000/movies/1 접속 /pages/movies/[id].js

import { useRouter } from "next/router";

export default function Detail() {
  const router = useRouter();
  console.log(router);
  return "detail";
}

=> console.log(router)에서 query: Object { id: “1” }를 얻을 수 있다.

  const router = useRouter();
  const onClick = (id) => {
    router.push(
      {
        pathname: `/movies/${id}`,
        query: {
          title: "hello",
        },
      },
      `/movies/${id}`
    );
  };
  return (
    <div className="container">
      <Seo title="Home" />
      {results?.map((movie) => (
        <Link href={`/movies/${movie.id}`} key={movie.id}>
          <div className="movie" onClick={() => onClick(movie.id)}>
            <img src={`https://image.tmdb.org/t/p/w500/${movie.poster_path}`} />
            <h4>{movie.original_title}</h4>
          </div>
        </Link>
      ))}
      ...

=> /movies/${id}를 넣어주면 masking 하여 query를 가려준다.

/pages/movies/[...id].js //object 형식으로 query를 보여줌
/pages/movies/[...params].js //params를 보여줌

import { useRouter } from "next/router";

export default function Detail() {
  const router = useRouter();
  console.log(router);
  const [title, id] = router.query.params || [];
  return (
    <div className="id">
      <h2>{title}</h2>
      <style jsx>
        {`
          .id h2 {
            color: white;
          }
        `}
      </style>
    </div>
  );
}

Catch All

Seo를 최적화하기 위해 getServerSideProps 사용

컴포넌트 내부에서 router를 사용하면 router는 프론트에서만 실행이 되지만
getServerSideProps 함수를 사용하므로 보류

404 에러

  • 잘못된 url 입력 시 보여줄 페이지

/pages/404.js