Next.js 프로젝트 초기화
npx create-next-app@latest
Next.js 프로젝트 초기화(+타입스크립트)
npx create-next-app@latest --typescript
색깔 #0070f3 이거 예뿜
npm run dev
자동적으로 내가 pages안의 index 파일에 넣은 것이 내 웹사이트에 home에서 보이고 있음.
library는 개발자로서 내가 사용하는 것. 내가 library를 불러와서 네가 library를 사용해서 무언가를 함
library를 사용할 때는, 내가 원하는 대로 코드를 작성할 수 있고 library는 사용하고 싶을 때 사용할 수 있음!
Ex) React: 렌더링할때 ReactDOM.render()를 불러와서 사용
React.js는 우리가 원할 때 부르고 원할 때 사용하는 library
framework는 나의 코드를 불러오는거임. 내 코드를 호출하는거.
만약 내가 코드를 적절한 위치에 잘 적기만 한다면, framework는 나의 코드를 불러와서 모든 걸 동작하게 할거임. 특정 규칙을 따라야함.
framework는 내가 코드를 적절한 곳(집)에 넣어야 하는거. 기본적으로 내가 그 집을 수정할 수 없음. 결국 우리는 framework의 게스트 느낌!
next.js는 자동적으로 우리가 pages안에 about이라는 페이지를 만들면, about에 갔을 때 그 component를 보여주는거야!
파일의 이름이 중요하다. 여기 파일의 이름이 그대로 우리 url로 들어가는거임
반면에 component의 이름은 그닥 중요하지 않아!
중요한 것은 그게 export default여야 한다는거야!
만약 default로 export하지 않는다면, 우리가 사이트에서 about에 들어갔을 때
에러가 발생하는 걸 볼 수 있어!
-> default export가 react component가 아니라고 함
유저에게 보여주고 싶은게 있다면, pages 폴더에서 export default function을 해야 함!
404 page도 공짜로 가지고 있음
앱의 홈은 기본적으로 index.js에서 나온거임
jsx를 쓰고 있다면 React.js를 import할 필요가 없다는거임
물론 만약 useState나 useEffect와 같은 react method를 쓰고 싶다면, 그런 경우에는 react.js를 import 해야함.
next.js의 가장 좋은 기능 중 하나는 앱에 있는 페이지들이 미리 렌더링 된다는 것
이것들은 정적으로 생성됨. 사전생성
유저가 페이지를 요청하면 그들은 진짜 HTML을 얻게 될거임!
유저가 웹사이트에 가면, 초기 상태의 component로 된 미리 생성된 HTML Page를 보게 되고, 상호작용이 일어나면 react.js는 그걸 받아서 아주 잘 작동하게 됨.
create react app은 client-side render를 하는 앱을 만듦
client-side redering (CSR)이 무슨 뜻이냐면, 브라우저가 유저가 보는 UI를 만드는 모든 것을 한다는 것을 의미함. 브라우저가 자바스크립트를 가져와서 client-side의 자바스크립트가 모든 UI를 만드는거지. 즉 브라우저가 HTML을 가져올 때 비어있는 div로 가져온다는 걸 의미함. 그 후 브라우저가 모든 자바스크립트를 요청해서 브라우저가 자바스크립트와 react.js를 실행시키고, 그 후에야 앱이 유저에게 보이게 될거야. UI가 만들어지는 것.
import Link from "next/link";
Link는 우리에게 NextJS 어플리케이션의 클라이언트 사이드 네비게이션을 제공해준다는거야
<a href="/">Home</a>
<a href="/about">About</a>
보다
<Link href="/">Home</Link>
<Link href="/about">About</Link>
가 훨씬 빠름!
아니면
<Link href="/" legacyBehavior>
<a>Home</a>
</Link>
우린 anchor를 사용하지 않음. Link를 씀.
useRouter()
앱의 함수 컴포넌트에서 router 객체 내부에 접근하려면 userRouter() hook을 사용할 수 있음.
modules라는 걸 사용
NavBar.modules.css
우리로 하여금 평범한 CSS를 사용할 수 있도록 해줌
<nav className={styles.nav}>
이런식으로 적용
클래스 이름을 JS Object에서의 Property 형식으로 적기 때문!
그리고 이러한 접근 방식의 장점으로는 실상 네가 이 클래스 이름을 살펴본다면, 이름이 다름! NextJS가 클래스 이름을 무작위로 설정! 그 말은 즉 다른 컴포넌트에서도 nav라는 클래스 이름을 사용할 수 있도록 하는거임!
<Link href="/">
<a
className={`${styles.link} ${
router.pathname === "/" ? styles.active : ""
}`}
>
Home
</a>
</Link>
<Link href="/about" legacyBehavior>
<a
className={[
styles.link,
router.pathname === "/about" ? styles.active : "",
].join(" ")}
>
About
</a>
</Link>
NavBar.module.css
.link {
text-decoration: none;
}
.active {
color: tomato;
}
module 좀 복잡하다,,
< style jsx>{`
CSS 스타일..
`}< /style>
styled jsx를 사용하기 때문에, 이 스타일들은 오직 이 컴포넌트 내부로 범위가 한정되는거임
<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>
Global Styles를 추가하는 방법
global이라는 Prop 추가하기
export default function Home(){
return (
<div>
<NavBar />
<h1 className="active">Hello</h1>
<style jsx global>{
` a{color:white;}`
}</style>
</div>
);
}
우리는 페이지별로 생각해야함
About 페이지로 갔을 때, 이 link들은 하얀색이 아닌 이유
그 이유는 우리가 About 페이지로 넘어갈 때, 우린 다른 페이지에 있기 때문임.
말 그대로 모든 페이지들에 전역적으로 스타일링 하고 싶다면 말이지
우리가 해야하는 건 다른 해결책임
App Component
NextJS가 모든 페이지를 렌더링할 수 있게 하는 일종의 어떤 컴포넌트의 청사진
_app.js 라는 파일을 만들어야함
왜냐면 NextJS는 About이 랜더링 되기 전에 먼저 App을 보기 때문
NextJS는 _app.js를 먼저 확인할 거고, 그 다음에 index.js의 내용물을 렌더링할거임 _app.js는 하나의 blueprint임
우리의 경우에는 모든 요소가 Next.js의 우산 아래에 존재하니까, 한 군데 통일되어 있다는게 좋음!
import Head from "next/head";
그러면 이 component안에 들어가는 모든 것들의 우리의 html의 head안에 보여질 거야.
Movies가 존재하지 않을 때, 그 안에 Loading 메시지가 들어갈거임
{!movies && <h4>Loading...</h4>}
Next.js를 이용해 API Keys를 숨기는거임!
const nextConfig = {
reactStrictMode: true,
async redirects() {
return [
{
source: "/old-blog/:path*",
destination: "/new-blog/:path*",
permanent: false,
},
];
},
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를 사용
https://nextjs.org/docs/api-reference/next.config.js/redirects
Rewrites (URL 변경되지 않음)
Rewrites를 사용하면 들어오는 request 경로를 다른 destination 경로에 매핑 가능
Rewrites은 URL 프록시 역할을 하고 destination 경로를 mask하여 사용자가 사이트에서 위치를 변경하지 않은 것처럼 보이게함
반대로 redirects은 새 페이지로 reroute되고 URL 변경 사항을 표시!
어떤 사이트들은 loading을 보여주지 않고, data가 들어옴과 동시에 render을 하기도 해
-> get server side props
getServerSideProps
page에서 서버 측 랜더링 함수인 getServerSideProps 함수를 export하는 경우 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 request에서 이 페이지를 pre-render 함.
getServerSideProps는 서버 측에서만 실행되며 브라우저에서는 실행되지 않음!
export async function getServerSideProps() {
const { results } = await (
await fetch(`http://localhost:3000/api/movies`)
).json();
return {
props: {
results,
},
};
}
이 function은 object를 return하게 되고, 이 object 안에는 props라는 key가 들어있음. 그리고 props key는 원하는 데이터를 아무거나 넣을 수 있어.
여기서 질문, 그 데이터를어디서 가져오는걸까?
export default function Home({ results })
요기서!
getServerSideProps는 오직 서버에서 실행됨
그리고 우리가 여기서 무엇을 return하던지, 이걸 props로써 page에게 주게 됨.
근까 원한다면 server side를 통해 props를 page로 보낼 수 있음!
이게 바로 우리에게 pageProps가 필요한 이유임!
그리고 Home 부분에 나타남
"/about"라는 URL의 about 페이지를 만들고 싶다면, "pages" 폴더 안에 "about.js" 파일을 만들어주면 됨!
"/movies"라는 URL을 만들고 싶다면, "pages" 폴더 안에 "movies.js"라는 파일을 만들면 되는거야
근데 이미 "/movies/all"가 있다면 "movies"라는 폴더 안에 "index.js"랑 "all.js"를 같이 넣어주면 됨
"movies" 폴더 안에 있는 "index.js"가 "/movies"에 맵핑될거고, "movies" 폴더 안에 있는 "all.js"가 "/movies/all"에 맴핑될거임
Next.js에 이것이 변수를 포함하는 Dynamic URL이다 라는 걸 알려주는 유일한 방법은 대괄호를 사용하는거임
Dynamic Routes
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 등과도 일치합니다. 일치하는 매개변수는 페이지에 쿼리 매개변수로 전송되며 항상 배열이므로 /movies/a 경로에는 다음 쿼리 개체가 있음
ex) { "id": ["a"] }
{
source: "/api/movies/:id",
destination: `https://api.themoviedb.org/3/movie/:id?api_key=${API_KEY}`,
},
source에 :id를 해줬다면 destination에도 :id도 해주ㅓ야함!
URL에 정보를 숨겨 보낼 수 있음
URL에서 URL로 state를 넘겨주는 방법
URL을 string으로 보낼 수도 있지만 객체로 보내줄 수도 있어
'as'는 브라우저의 URL을 마스킹 해
router.push(
{
pathname: `/movies/${id}`,
query: {
title,
},
},
`/movies/${id}`
);
여기에 콤마를 해주고 브라우저에 보일 URL을 써줘
<Link
legacyBehavior
href={{
pathname: `/movies/${movie.id}`,
query: {
title: movie.original_title,
},
}}
as={`/movies/${movie.id}`}
>
router.push(url, as, options)
클라이언트 측 전환을 처리
이 방법은 next/link가 충분하지 않은 경우에 유용
url: UrlObject | String: 탐색할 URL
as: UrlObject | String: 브라우저 URL 표시줄에 표시될 경로에 대한 선택적 데코레이터
router.push({
pathname: '/post/[pid]',
query: { pid: post.id },
})
catch-all URL은 뭐든 캐치해내는 URL임.
홈페이지에서 클릭해서 돌아오지 않더라고 상세페이지에서 영화 제목을 볼 수 있음
우리가 할 건 여기 파일명을 바꾸는거임! ([id]) 지금은 단 한개의 변수만 받고 있잖아? 근데 [...id] 해주면 여러개 된당
영화 제목이 있고 그 다음에는 영화 ID가 나오는거임!
API에서 요청을 처리하는 동안에는 로딩 단계를 보여줌
보통의 useState, useEffect를 사용해서 말야!
이전에는 Detail component 내부에서 router를 사용했었음
하지만 컴포넌트 내부에 들어있는 router는 client side에서만 실행됨
만약 URL에 들어있는 영화제목을 사용해서 구글 seo에 최적화하고, 유저가 접속하기 전에 탭 제목을 바꾸고 싶고, 기본적으로 걍 이 페이지를 pre-render하고 싶다면
그 때에는 server-side에서 정보를 얻기 위한 getServerSideProps를 실행하면 됨
server-side에서 받아온 정보를 페이지로 넘겨오면 페이지는 그 정보를 받아서 보여주는거야. 그럼 server-side에서 pre-render된 꼴이 되는거지
getServerSideProps
페이지에서 getServerSideProps(서버 측 렌더링)라는 함수를 export하는 경우 Next.js는 getServerSideProps에서 반환된 데이터를 사용하여 각 request에서 이 페이지를 pre-render 함
getServerSideProps (Context parameter)
params: 이 페이지에서 dynamic route(동적 경로)를 사용하는 경우 params에 route parameter가 포함.
페이지 이름이 [id].js이면 params는 { id: ... }처럼 보임
query: 쿼리 문자열을 나타내는 객체
pages/404.js 만들어주기
export default function NotFound() {
return "what are u doing here?";
}