Next JS 기초
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>
);
}
네비게이팅
Link
💡 네비게이팅 할 때 <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.jsmodule.exports = { reactStrictMode: false, async redirect() { return [ { source: "/old-blog", destination: "/new-blog", permanent: false, }, ]; }, };💡premanent :
rewrites
- 위의 redirects와 동일하나 destination을 보여주지 않는다.(Masking)
next.config.jsmodule.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