노마드코더 영화 앱 만들기(Next.js)
프로젝트 생성
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 폴더 안에서 무언가를 만드는 것 뿐이다.
내가 한 일이라곤 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에서만 실행되는 것이다.
'한 걸음 > React & Next.js' 카테고리의 다른 글
Numble '다른 색깔 찾기 게임 제작 챌린지' -3 (게임 플레이 로직) (0) | 2022.02.12 |
---|---|
Numble '다른 색깔 찾기 게임 제작 챌린지' -2 (빙고판 구현, random color array 생성) (0) | 2022.02.12 |
Numble '다른 색깔 찾기 게임 제작 챌린지' -1 (개발순서, 컴포넌트 구조, 카운트다운 로직구현) (0) | 2022.02.07 |
[React, typescript] 다른 컴포넌트에 props로 함수 넘겨주기 (1) | 2022.02.06 |
Tailwind CSS 프로젝트 셋팅 (0) | 2022.02.05 |