npx create-next-app@latest
타입스크립트를 사용하고 싶다면 npx create-next-app@latest --typescript (타입스크립트가 좋긴함)
jsx를 쓰기 위해 별도로 리액트를 import 필요는 없지만, useState나 useEffect 같은 react method(hooks)를 쓰고 싶으면 react.js를 import 해야함
import { useState } from "react";
노드 버전 안맞는 에러 발생
v16.15.0 노드로 재 다운로드
npm run dev로 실행
* Library vs Framework
: 라이브러리는 개발자로서 내가 가져다 사용하는 것. => 자유도가 높음
: 프레임워크는 나의 코드를 불러오는 것 => 해당 프레임워크의 특정한 규칙을 따라야함
* pages에 파일을 만들면 NextJS가 알아서 그 이름으로 URL을 만들어 줌 (대박적.. 쌩 리액트 쓰면 라우터 설계부터 컴포넌트 설계까지 단계적으로 생각하고 구현할 게 많았는데 시간절약이 많이 되는듯!!)
+ 없는 url 접근시 404페이지도 제공...(리액트에선 그냥 만들어야 됨ㅠㅠ)
//pages>about.js
export default function Potato(){//컴포넌트 이름은 아무거나 상관없음. 중요한건 export default
return "Hello";
}
* next.js의 장점 중 하나는 앱에 로드되는 페이지들이 미리 렌더링 되어있다는 점 (static 상태로 생성) => SSR
* 라우터에 next/link 사용 (일반 a태그 사용시 ESLint 에러 발생, 페이지 새로고침 됨) => 페이지 새로고침X
class나 style을 사용하기 위해서는 Link 안에 anchor(a태그)에 적용해주어야함
//conponents>NavBar.js
import Link from "next/link";
export default function NavBar(){
return(
<nav>
<Link href="/">
<a className="hello">Home</a>
</Link>
<Link href="/about">
<a style={{color:red}}>About</a>
</Link>
</nav>
)
}
라우터에 hook 적용하기 => next/router 사용
//conponents>NavBar.js
import Link from "next/link";
import { useRouter } from "next/router";
export default function NavBar(){
const router = useRouter();
return(
<nav>
<Link href="/">
<a style={{color : router.pathname === "/" ? "red":"blue"}}>Home</a>
</Link>
<Link href="/about">
<a style={{color : router.pathname === "/about" ? "red":"blue"}}>About</a>
</Link>
</nav>
)
}
* NextJS에 CSS 추가해보기
1. css를 모듈로 만들어서 import 하는 방식 사용 : 클래스 이름을 다 알아야하는 단점이 있움.
//components>NavBar.module.css
.nav{
display:flex;
justify-content : space-between;
backgroud-color : tonato;
}
//components>NavBar.js
import { useRouter } from "next/router";
import styles from "./NavBar.module.css";
export default function NavBar(){
const router = useRouter();
return(
<nav className={styles.nav}>
<Link href="/">
<a>Home</a>
</Link>
<Link href="/about">
<a>About</a>
</Link>
</nav>
)
}
2. styles JSX 사용 : 사용컴포넌트 안에서만 css 적용됨, js로써 props를 갖다쓸 수 있음
//conponents>NavBar.js
import Link from "next/link";
import { useRouter } from "next/router";
export default function NavBar(){
const router = useRouter();
return(
<nav>
<Link href="/">
<a className={{color : router.pathname === "/" ? "active":""}}>Home</a>
</Link>
<Link href="/about">
<a className={{color : router.pathname === "/about" ? "active":""}}>About</a>
</Link>
<style jsx>{`
nav{
backgroud-color:tomato;
}
a{
text-decoration:none;
}
.active{
color:yellow;
//color: ${props.color]
}
`}</style>
</nav>
)
}
3. 전역 css 적용해보기
style jsx global 사용 => 페이지 단위로 적용
<style jsx global>
{`
` a{
color : blue;
}
`}
</style>
모든 페이지에 적용하려면...? NavBar랑 font-size 같은거 전체 app에 적용하고 싶으면!!! => app.js활용
pages에 _app.js 파일 생성 (이름 꼭 _app.js 여야함!!! 그래야 다른 페이지 만들기 전에 NextJS가 여길 먼저 읽어감)
(+ 페이지, 컴포넌트에 css를 임포트 하기 위해선 반드시 module이어야함, 하지만 _app.js 에서는 모든 global styles을
임포트 할 수 있음!!)
//pages>_app.js
import NavBar from "../components/NavBar";
import "../styles/globals.css"; //글로벌 스타일 임포트 가능, 여기에 폰트같은거 두면 설정됨!
export default function App({Component, pageProps}){
return (
<>
<NavBar />
<Component {...pageProps} />
<style jsx global>
{`
a{
color : blue;
}
`}
</style>
</>
);
}
미니 무비앱 만들기 실습
*NextJS가 제공하는 head 사용해보기
//pages>index.js
import Head from "next/head";
export default function Home(){
return(
<div>
<Head>
<title>Home | Next Movies</title>
</Head>
<h1>Home</h1>
</div>
);
}
//pages>about.js
import Head from "next/head";
export default function About(){
return(
<div>
<Head>
<title>About | Next Movies</title>
</Head>
<h1>About</h1>
</div>
);
}
이렇게 하면 모든 페이지에 복붙해야하니까 좀 더 스마트 하게 하려면?...
컴포넌트로 만들기!
//components>Heads.js
import Head from "next/head";
export default function Heads({title}) {
return(
<Head>
<title>{title} | Next Movies</title>
</Head>
);
}
이러면 Heads 컴포넌트를 불러와서 쓸수 있음.
//pages>index.js
import Head from "next/head";
import Heads from "../components/Heads";
export default function Home(){
return(
<div>
<Heads title="Home">
<h1>Home</h1>
</div>
);
}
* Fetching Data
API key 숨겨보기
1. redirect => next.config.js 파일
//next.config.js
module.exports = {
reactStrictMode true,
async redirects(){
return[
{
source:"/test", //여기 url로 들어오면
destination:"/home", //이리로 리다이렉트해줌(https://www.google.com 외부도됨
permanent:false //영구적으로 쓸지 브라우저나 검색엔진이 기억하는 여부 결정
}
]
}
}
config 파일은 수정 후 서버 재시작 필요 npm run dev
source:"/old-blog/:path*" 설정해주고 destination:"/new-blog/:path*" 설정해주면
url 에 old-blog/ 뒤에 뭐라고 치든 그 url 이 보존되어 new-blog url로 이동됨.
2. rewrites => next.config.js 파일
//next.config.js
const API_KEY = "1234560";
module.exports = {
reactStrictMode true,
async rewrites(){
return[
{
source:"/api/movies",
destination:`https://api.themoviedb.org/어쩌고?api_key=${API_KEY}`,
permanent:false //영구적으로 쓸지 브라우저나 검색엔진이 기억하는 여부 결정
}
]
}
}
redirect와 비슷하지만 유저가 url 변화를 볼 수는 없음.
이러한 방식으로 NextJS는 masking을 실행하고, 사용자는 API Key를 볼 수 없도록 숨길 수 있음.
+ .env 파일 만들어서 API_KEY를 빼둘 수 도 있음! .env는 gitignore 필수
//pages>index.js
import {useEffect, useState} from "react";
import Heads from "../component/Heads";
export default function Home(){
const [movies, setMovies] = useState();
useEffect(() => {
(async () => {
const { results } = await (await fetch(`/api/movies`)).json();
setMovies(results);
})();
}, []);
return(
<div className="container">
<Heads title="Home" />
{!movies && <h4>Loading...</h4>}
{movies?.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>
)}
<style jsx>{`
.container {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 20px;
gap: 20px;
}
.movie img {
max-width: 100%;
border-radius: 12px;
transition: transform 0.2s ease-in-out;
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
}
.movie:hover img {
transform: scale(1.05) translateY(-10px);
}
.movie h4 {
font-size: 18px;
text-align: center;
}
`}</style>
</div>
);
}
//출처 : https://github.com/nomadcoders/nextjs-fundamentals/blob/ebe7016cb04f5d4dd93e317704b963bc91516c1d/pages/index.js#L1-L45
* Server Side Rendering
getServerSideProps()라는 function 을 export (이름 바꾸면 안됨!!!!)
getServerSideProps 는 server에서 실행, 여기에 무엇을 리턴하던지 이걸 props 로써 page에 주게 됨.
//pages>index.js
import { useEffect, useState } from "react";
import Heads from "../component/Heads";
export default function Home({result}){//pageProps 데이터 받음.
return(
<div className="container">
<Heads title="Home" />
{
}
</div>
);
}
export async function getServerSideProps(){//이름 고정, 서버단에서 데이터불러옴.
const { result } = await (
await fetch(`http://localhost:3000/api/movies`)//절대주소 풀로 적어줌
).json();
return{
props : {
results, //여기서 무엇을 return 하던지 이걸 props로써 _app.js page에 건넴.
//_app.js보면 <Test {...pageProps}/> 이런식으로 건네줌
},
};
}
* Dynamic Routes
Next.js에는 라우터 개념이 없으니 pages에 적용.
만약 /movies/all이라는 url을 구현하고 싶다면 pages 폴더 안에 movies 폴더 만들고 all.js 파일 생성 하면 됨.
만약 /movies 라고만 구현 하고 싶다면? pages 폴더 안에 movies 폴더 안에 index.js 파일 생성하면 됨.
(movies 안에 다른 하위 url 이 없다면 pages 폴더 안에 그냥 movies.js 파일로 만들면 됨.)
영화의 id를 받아서 상세 페이지 구현하기
pages 폴더에 movies 폴더에 [id].js 파일 만들기 => 배열로 변수 파일 이름만들면 됨..신기.... 대괄호를 이용한 다이나믹 라우터 구현.
Link를 통한 navigating이 아닌 코드를 통해 자동으로 navigating 하는 방법 => router hook 사용
const onClick = (id) => {
router.push(`/movies/${id}`);
};
<div onClick={() => onClick(moovie.id)} ></div>
하지만 위와 같이 router.push를 하거나 Link를 사용하는 것 외에도 url 에 정보를 숨겨서 전달 할 수 있음.
url 에서 url로 state를 넘겨주는 방법!!
router.push 할때 string이 아닌 as를 사용. (url마스킹)
//pages>index.js
...
const onClick = (id, title) => {
router.push(
{
pathname : `/movies/${id}`,
query : {
title,
},
},`/movies/${id}` //as 사용하면 원하는 url로 마스킹 할 수 있음.
);
};
<div onClick={() => onClick(moovie.id, movie.original_title)}
className="movie" key={movie.id}></div>
...
//만약 Link에서 동일하게 url 마스킹을 하고싶다면?
<h4>
<Link
href=({
pathname : `/movies/${movie.id}`,
query : {
title : movie.original_title,
},
})
as = {`/moives/${movie.id}`}
>
<a>{movie.original_title}</a>
</Link>
</h4>
//pages>movies>[id].js
import {useRouter} from "next/router";
export default function Detail(){
const router = useRouter();
return <div>
<h4>{router.query.title || "Loading..."}</h4> //홈에서 상세감시 페이지로 넘어올때만 보임.
</div>
}
* catch-all url
[...id].js 이런 식으로 파일을 만들면 무한 url을 만들 수 있음
url에 /movies/a/b/c/d/e/f/g 이렇게 치면
console로 query.params 에 배열로 ["a","b","c"...] 이렇게 들어있는걸 확인 가능.
//pages>movies>[...params.js]
import Heads from "../../components/Heads";
import {useRouter} from "next/router";
export default function Detail({params}){
const router = useRouter();
const [title, id] = params || [];
return(
<div>
<Heads title={title}/>
<h4>{title}</h4>
</div>
);
}
export function getServerSideProps({params : {parmas}}){
return(
props : {
params,
},
);
}
* 404 커스텀
pages 에 404.js 만들면 됨
'스터디 > React' 카테고리의 다른 글
[Next.js] render 가 두번씩 되는 현상. (0) | 2022.06.20 |
---|---|
[prisma] next 프레임워크에 prisma 연동해보기 (풀쿼리) (0) | 2022.05.19 |
[Hooks] 실전형 리액트 Hooks (0) | 2022.05.17 |
[SSR/CSR] 빠른 view를 위하여 (0) | 2022.05.10 |
[노마드코더 ReactJS] React JS 로 영화 웹서비스 만들기 (0) | 2022.05.04 |