노마드코더 영화 앱 만들기(Next.js)

2022. 2. 11. 14:16
반응형

프로젝트 생성

npx create-next-app@latest

npx create-next-app@latest --typescript (타입스크립트)

 

프로젝트 실행

npm run dev

<Next.js 프로젝트의 package.json>

<React 프로젝트의 package.json>

"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
},
  • react로 만든 프로젝트에서는 npm start를 사용하는데... npm run dev는 뭘까?
  • run은 npm에 기본적으로 설정된 4가지 -start(시작), stop(정지), restart(재시작), test(테스트)- 이외의 scripts를 실행하는 명령어다. (=dev는 기본 설정된 4가지 스크립트에 포함되지 않기 때문에 run을 붙여 실행하는 것이다. npm run build 또한 같은 맥락)
  • next.js의 package.json 파일에는 dev도 있고 start도 있는데... 각각은 무엇인가?"npm start": 프론트 실행
  • "dev": 프론트 및 서버를 동시에 실행
  • npm start 입력해도 에러가 난다면?
  • 최초 한 번은 npm run build를 통해 앱을 빌드해야 한다. 그 후로는 npm start를 입력하면 로컬 화면이 뜨는데... 근데 껐다 켜야만 바뀐 내용이 적용된다...? 무슨 차이가 있는지 더 알아봐야겠다...

 

 


 

library VS framework

 

라이브러리 (React.js) 자유도👍 편리함👎

라이브러리는 내가 개발자로서 사용하는 것이다. 내가 라이브러리를 불러와서, 라이브러리를 사용해 뭔가를 하게 된다. 라이브러리는 내가 원하는대로 코드를 작성해서 사용하고 싶을 때 사용할 수 있다.

react 프로젝트를 새로 만들었을 때, 맨 처음 AppComponent부터 시작한다. 개발자는 이 빈 공간에 원하는 폴더를 만들어 원하는 구조를 구성하고, 원하는 코드를 짜 넣을 수 있다. 폴더이름을 Components라고 짓지 않아도 되고, 이 폴더를 어디에다 두어도 상관없다. 개발자의 자유다.

프레임워크 (Next.js) 자유도👎 편리함👍

반면, 프레임워크는 나의 코드를 그것이 마땅히 있어야 할 곳으로 불러오는 것이다. 내가 적절한 위치에 원하는 코드를 잘 적어넣기만 한다면, 프레임워크는 알아서 그 코드를 자신만의 방식대로 동작하게 만들어줄 것이다.

next.js에서 우리는 그들이 이미 정의해둔 특정한 규칙에 따라야 한다. 이를 따라야지만 프로그램이 정상적으로 작동한다. 예를 들어 next.js로 만든 프로젝트에서는 개발자가 ReactDOM.render을 직접 접근해서 커스텀할 수 없다(이 작업은 우리가 알 수 없는 저 깊숙한 곳에서 벌어지고 있다). 우리가 할 수 있는 것은 오직 pages 폴더 안에서 무언가를 만드는 것 뿐이다.

 

 

next.js는 알아서 제법 멋진 404 페이지까지 제공한다.

내가 한 일이라곤 pages 폴더 생성 후 about.js 파일을 만든 것 뿐이다.

즉, 저절로 파일명~~(export하는 함수명은 중요하지 않다)~~이 url이 된 것이다. 나는 라우팅 처리 같은 걸 따로 하지 않았다.

다만, pages가 아니라 다른 이름이거나 export를 하지 않았다면 이 작업은 유효하지 않을 것이다.

 

 

 


Static Pre Rendering

 

React라면?

크롬이 react.js와 우리의 코드를 다운받았을 때, 유저는 모든 것들의 렌더링이 완료되었을 때 이것들을 보게 된다. 클라이언트 사이드의 자바스크립트가 모든 UI를 구성하기 때문이다~~(만약 크롬이 제공하는 기능을 통해 자바스크립트를 비활성화한다면, 우리는 react로 만든 웹사이트를 볼 수 없을 것이다).~~

또한 인터넷이 아주 느린 환경이라면, 크롬은 javascript를 느리게 받아오게 되고 우리의 웹사이트 또한 느리게 뜨게 될 것이다. (흰 화면만 오래 보고 있는 상황 - 좋지 않은 유저경험)

 

Next.js에서는?

반면, 매우 느린 인터넷 환경이라 할지라도 next.js로 만든 앱에서 유저는 최소한 html화면을 볼 수는 있다(API를 사용해서 불러오는 정보는 위와 똑같이 느릴 테지만).

next.js는 react.js를 백엔드에서 동작시켜 페이지를 미리 만들어두는데, 렌더링이 끝났을 때 이것이 html이 되고, 이것을 페이지의 소스코드에 넣어준다. 그러면 유저는 자바스크립트 및 react.js가 미처 로딩되지 않았더라도 콘텐츠를 볼 수 있게 되는 것이다. 추후 react.js가 로딩되었을 때, 기본적으로 이미 존재하는 것들과 연결되어 일반적인 react.js앱이 된다.

즉, 유저는 초기상태로 미리 생성된 html을 보고있다가 상호작용이 일어났을 때 react.js와 잘 결합된 완전한 웹사이트를 볼 수 있다. 이는 모든 것이 로딩될 때까지 빈 화면을 보며 기다리지 않아도 된다는 것이다.

 


 

next.js에서 네비게이터로 <a>태그를 사용하려면?

다른 페이지로 보내기 위해 페이지 전체를 새로고침하는 비효율적인 문제가 발생한다. import Link from ‘next/link’ 를 통해 <a>태그 대신 <Link href=”/”>를 사용해주어야 한다. react의 react-router-dom에서 사용하는 <Link>와 같다.

만약 <Link>에 스타일을 주고 싶다면, <Link><a>...</a></Link> 와 같은 형태로 사용해야 한다.

react의 useRouter와 같이, useRouter를 사용해서 조건에 따른 스타일링을 아래처럼 구현할 수 있다.

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

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

 

스타일링

 

방법 1) module.css 파일로 분리

인라인 스타일링을 하고싶지 않다면, (파일명).module.css 파일을 만들어 정리하는 방법이 있다. 이 파일은 각 components 파일과 같은 경로에 위치한다.

만약 2개의 className을 동일 태그에 적용하고 싶다면, ${ } 형태로 넣어줄 수 있다.

import styles from "./NavBar.module.css";

export default function NavBar() {
  return (
		
		// className을 아래와 같이 쓰면 
	  // 무작위 클래스명이 생성되어 충돌을 막아준다
    <nav className={styles.nav}>
      ...
    </nav>
  );
}
// NavBar.module.css 

.nav {
	//css 작성
}

위의 a 태그에서 사용했던 조건부 스타일링도 마찬가지로 인라인 스타일보다 className을 활용해서 보기 좋게 바꿀 수 있다.

import styles from "./NavBar.module.css";

export default function NavBar() {
  const router = useRouter();
  return (
    <nav>
      <Link href="/">
        <a className={router.pathname === "/" && styles.active}>Home</a>
      </Link>
    </nav>
  );
}

다만, 위와 같이 스타일을 .module.css 파일로 분리하여 적용하는 방법은 아래와 같은 단점을 가진다.

① 파일을 2개로 나눠야 한다

② module 파일에서 각 클래스들의 이름을 기억해야 한다

 

방법 2) styled jsx

next.js의 고유 방법인 styled jsx는 해당 컴포넌트 안에 <style jsx>{$ ...css코드작성... }</style> 와 같은 형태로 직접 스타일링 코드를 넣어주는 방식이다.

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

    <style jsx>{`
      a {
        color: gray;
        margin-right: 1rem;
      }
			.active {
				color: white;
			}
    `}</style>
</nav>

방법 1과 반대로 파일을 따로 나눌 필요가 없고, 클래스명을 고민할 필요 없다는 장점이 있다. module.css 파일에서 한 스타일링과는 중첩되지 않으므로, 방법1+2를 섞어서 사용할 수는 없다. 코드가 작성된 해당 컴포넌트만 적용 범위이다(=다른 anchor들에게 영향을 미치지 않음)

<style jsx global> 과 같은 형태로 사용하면 전역변수로 지정할 수 있으며, 이는 pages폴더 안의 _app.js 파일 안에서 관리한다.


 

_app.js 파일

next.js는 index를 렌더링하기 전에 먼저 _app.js를 먼저 확인하고, 그 후 index.js의 내용을 확인한다.

// Component, pageProps는 nextJS가 정의한 룰
export default function App({ Component, pageProps }) {
  return (
    <div>
      <Component {...pageProps} />
    </div>
  );
}

 


 

Next.js가 제공하는 작은 패키지들

import head from ‘next/head’

→ react.js로 만든 프로젝트라면 head 부분을 구현하기 위해 쓸 노력을 절감할 수 있다.

→ react.js 프로젝트에서 helmet 등 외부 패키지를 다운 받아 사용한다면, 우리 프로젝트 안에 모르는 부분들이 생기게 된다. 이는 우리가 모르는 에러나 버그가 발생할 가능성을 높일 수 있다.

 

import Head from "next/head";

export default function About () {
  return (
    <div>
      <Head>
        <title>About | Next Movies</title>
      </Head>
    </div>
  );
}

 

 


 

외부API 이용해서 영화 DB 가져오기

TMDB 사이트 가입 → setting → api 탭에서 key 얻기 → API Docs 참고하여 이용 (로딩 매우 느림)

 

 


 

Redirect

next.config.js 파일을 아래와 같이 수정한다.

module.exports = {
  reactStrictMode: true,

  async redirects() {
    return [
      {
        source: "/contact", // 만약 contact라는 주소를 입력한다면
        destination: "/form", // form으로 redirect 해준다
        permanent: false, // 브라우저, 검색엔진이 이 정보를 기억할 것인지 여부
      },
    ];
  },
};

아래와 같이 응용할 수도 있다.

module.exports = {
  reactStrictMode: true,

  async redirects() {
    return [
      {
        source: "/old-blog/:path*", // :path는 뒤에 어떤 문자열이 오든 상관없다는 의미
        destination: "/new-blog/:path*", // 뒤에 붙이는 *은 모든 것을 catch 할 수 있다는 의미
        permanent: false,
      },
    ];
  },
};

반면 rewrite는 마찬가지로 새로운 주소로 redirect되긴 하지만 URL은 변하지 않는다(=유저가 주소창에서 url이 바뀌는 모습을 볼 수 없다)

이를 활용하여 유저가 개발자도구 등을 열어 API key를 찾을 수 없도록 숨길 수 있다.

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

 

코드 상에 사용된 API key 깔끔하게 정리하기

 

1) .env 파일 생성 후 아래와 같이 입력

API_KEY=a2428d69c5d6a06...(생략)

 

2) API key를 사용하는 파일에서 .env파일 안에 있는 값을 사용하겠다고 선언

3) .gitignore 파일의 #vercel 부분에 .env를 추가해주어야 github repository에 .env 파일이 올라가지 않는다.

 

 

 


 

getServerSideProps

어떤 사람은 pre rendering을 하지 않고, 데이터가 모두 불러와졌을 때 비로소 페이지를 보여주고 싶을 수도 있다. 이 때 필요한 것이 바로 서버사이드 렌더링이다.

서버사이드 렌더링을 하기 위해서는 아래와 같은 함수를 만들어야 한다. 이 때 사용되는 getServerSideProps라는 이름이 포인트다(이 이름은 next.js에서 정의한 룰이기 때문에 마음대로 바꿀 수 없다)

export function getServerSideProps() {
  ...
}

위 함수 안에 들어간 내용은 오직 server side에서만 실행되는 것이다.

 

 

반응형

BELATED ARTICLES

more