본문 바로가기
내일배움캠프/Today I Learned

[TIL 2023.08.04] Next.js 미니 영화 앱 만들기

by 괴코딩 2023. 8. 4.

💻오늘 배운 내용

Redirect and Rewrite

next.config.js
Next.js에서 커스텀 설정을 하기 위해서는 프로젝트 디렉터리의 루트(package.json 옆)에 next.config.js 또는 next.config.mjs 파일을 만들 수 있다. -next.config.js는 JSON 파일이 아닌 일반 Node.js 모듈-
Next.js 서버 및 빌드 단계에서 사용되며 브라우저 빌드에는 포함되지 않는다.

Redirects (URL변경됨)
Redirect을 사용하면 들어오는 request 경로를 다른 destination 경로로 Redirect할 수 있다. Redirect을 사용하려면 next.config.js에서 redirects 키를 사용할 수 있다.

redirects은 source, destination 및 permanent 속성이 있는 객체를 포함하는 배열을 반환하는 비동기 함수이다.

 

source: 들어오는 request 경로 패턴 (request 경로)
destination: 라우팅하려는 경로 (redirect할 경로)

permanent: true인 경우 클라이언트와 search 엔진에 redirect를 영구적으로 cache하도록 지시하는 308 status code를 사용하고, false인 경우 일시적이고 cache되지 않은 307 status code를 사용한다.

 

const nextConfig = {
  reactStrictMode: true,
  async redirects() {
    return [
      {
        source: '/old-blog/:path*',
        destination: '/sexy-new-blog/:path*',
        permanent: false,
      },
    ];



Rewrites (URL변경되지 않음)
Rewrites를 사용하면 들어오는 request 경로를 다른 destination 경로에 매핑할 수 있다.
Rewrites은 URL 프록시 역할을 하고 destination 경로를 mask하여 사용자가 사이트에서 위치를 변경하지 않은 것처럼 보이게 한다. 반대로 redirects은 새 페이지로 reroute되고 URL 변경 사항을 표시.

 

const nextConfig = {
  reactStrictMode: true,
  async rewrites() {
    return [
      {
        source: '/api/movies',
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`,
      },
    ];
  },
};



Movie Poster Path

`https://image.tmdb.org/t/p/w500/${movie.poster_path}`



주의! fetch할 때 /api/movies 또는 http://localhost:3000/api/movies 둘 다 가능하지만 http가 아닌 https로 fetch하게 되면 오류가 발생한다.

export async function getServerSideProps() {
  const res = await fetch('http://localhost:3000/api/movies');
  const { results } = await res.json();

  return {
    props: {
      results,
    },
  };
}

 

Server Side Rendering

getServerSideProps
page에서 서버 측 랜더링 함수인 getServerSideProps함수를 export하는 경우 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 request에서 이 페이지를 pre-render한다. getServerSideProps는 서버 측에서만 실행되며 브라우저에서는 실행되지 않는다.

 

즉 HTML이 클라이언트 사이드에서 자바스크립트를 통해 생성이 되는 게 아니라 Next.js가 사전에 각 페이지를 만들어 놓는다. 이때 각 HTML은 해당 페이지에 최소한으로 필요한 자바스크립트 코드와 결합되어있다. 페이지가 브라우저에 의해 로드될 때는 hydration이라는 프로세스를 거치게 된다. hydration은 자바스크립트 코드가 실행되어 해당 페이지를 완전히 인터렉티브하게 만드는 것을 의미한다.


프리 렌더링을 할 경우, 프리 렌더링을 하지 않을 때보다 더 나은 성능과 SEO를 갖출 수 있다.

 

getServerSideProps vs getStaticProps

getServerSideProps 👉 매 요청 시에 실행된다.

getStaticProps 👉 빌드 시에 실행된다. (즉 딱 한 번 실행된다.)

 

Dynamic Routes

미리 정의된 URL 주소로만 라우팅하는 것이 아니라 사용자가 접근한 경로 혹은 상황에 따라 동적인 라우팅을 제공하고 싶을 때 사용할 수 있는 방식이다.

 

예를들어, /my-profile/ 뒤에 이름을 주어서 회원들의 프로필을 표현하고 싶다면? /my-profile/ray-kim 페이지에서는 ray-kim 의 프로필을 제공하고, /my-profile/jake-seo 페이지에서는 jake-seo 의 프로필을 제공하고 싶을 때 사용할 수 있다.


Next.js에서는 page에 대괄호([param])를 추가하여 Dynamic Route를 생성할 수 있다.
/movies/1, /movies/abc 등과 같은 모든 경로는 pages/movies/[id].js와 일치한다.

const router = useRouter()
const { id } = router.query


Catch all routes
대괄호 안에 세 개의 점(...)을 추가하여 모든 경로를 포착하도록 Dynamic Routes를 확장할 수 있다.

pages/movies/[...id].js는 /movies/1와 일치하지만 /movies/1/2, /movies/1/ab/cd 등과도 일치한다. 

// 예시 
import { useRouter } from 'next/router'

const Movies = () => {
  const router = useRouter()
  const { id } = router.query

  return <p>Movies: {id}</p>
}

export default Post

위의 소스코드에서 pid 값을 router.query 오브젝트를 통해 가져오고 있는데, router.query 오브젝트 내부의 pid 프로퍼티 값은 경로에 의해 설정된다.

/movie/123 경로에 접근했을 때, router.query 내부의 프로퍼티 값은 123 이 된다.

 

일치하는 매개변수는 페이지에 쿼리 매개변수로 전송되며 항상 배열이므로 /movies/a 경로에는 다음 쿼리 객체가 있다.

{ "id": ["a"] }

post/123?foo=bar 경로에 접근한다면, router.query 내부의 값은 다음과 같을 것이다.

{"pid": "123", "foo": "bar"}

 

❓발생한 이슈/고민

TMDB API를 이용해서 간단한 영화 정보페이지 만들기

 

💡해결과정

오늘 배운 것을 이용하여 간단한 영화체이지 만들기를 따라해보았다.

 

처음에 자꾸 fetch 오류가 나서 당황스러웠는데 검색해보니 데이터를 가져올 때,

http가 아닌 https로 fetch하게 되면 오류가 발생한다고 한다.

 

또,

이미지 태그마다 <img> 태그보다 <Image> 태그를 쓸 것을 권고하고 있는데,

Next/Image 컴포넌트에서 제공하는 대표적인 기능은 다음의 3가지다.

  • lazy loading : 이미지 로드하는 시점을 필요할 때까지 지연시키는 기술. 예를 들면 스크린 밖에 있는 이미지들은 로딩을 지연시키고 스크린 안에 있는 이미지만을 로드해서, 불필요한 대역폭 사용을 줄이고 필요한 이미지만 빠르게 로드할 수 있도록 하는 것
  • 이미지 사이즈 최적화 : 디바이스 크기 별로 srcSet을 미리 지정해두고, 사용자의 디바이스에 맞는 이미지를 다운로드할 수 있게 지원하고, 이미지를 webp와 같은 용량이 작은 포맷으로 이미지를 변환해서 제공.
  • placeholder 제공: 레이아웃이 흔들리는 현상을 방지하기 위해 placeholder를 제공. 이미지가 로드되기 전에도 이미지 높이만큼 영역을 표시해서 이미지가 로드된 후에 레이아웃이 흔들리지 않도록 하는 것

즉, Next/Image를 사용하면 얻을 수 있는 장점은 

  • 성능 향상: 디바이스마다 적절한 사이즈의 이미지를 서빙하고, webp와 같은 작은 용량의 포맷을 사용함
  • 시각적인 안정성: 이미지 로드 전 placeholder를 제공하여 CLS(Cumulative Layout Shift) 방지
  • 빠른 페이지 로딩: viewport에 들어왔을 때만 이미지를 로드하고, 작은 사이즈의 blur 이미지를 미리 로딩하여 사용자에게 더 빠른 페이지를 보여줄 수 있음

그렇지만 이번에는 강의 따라서 그냥 img 태그로 작성했다. css부터 내가 다 새로 짜야하기에...

완성한 페이지

 

🧐궁금점과 부족한 내용

fetching data 함수를 보면서 특이한 구조를 발견했다.

 useEffect(() => {
   (async () => {
     const { results } = await (
       await fetch('/api/movies')
     ).json();
     setMovies(results);
   })();
 }, []);

await (데이터 가져오는 로직) ( ) << 이런 구조인데, 처음 봤을 때 왜 괄호를 두 번이나..? 라고 생각했다.

 

async 함수를 바로 선언하고 호출하기 위해 두 개의 괄호로 감싸주는 형태의 함수를

IIFE(Immediately Invoked Function Expression)라고 한다. (함수를 정의하자마자 즉시 실행)
: 익명 함수를 일회성으로 호출하며, 스코프를 막기 위해 함수 내부를 괄호로 감싸주는 것이다.

 

오...

 

📋레퍼런스

https://nextjs.org/docs

반응형