라이브러리는 우리가 사용하는 것
프레임워크는 우리의 코드를 불러오는것
di(dependency injection)의 개념과 유사
커다란 차이 중에는 ReactDOM.render부분이 없다는 것
이런 과정을 절대로 커스터마이징 할 수 없음
우리가 할 수 있는 유일한 부분은 pages안에 만드는 것임
export default를 안 했을 경우 next가 예쁘게 에러 메세지를 만들어 줌
server side rendering
그냥 하나의 div로만 되어 있고, 나머지는 전부 다 js로 되어 있다는 것들이 조금 특이한 점
client side render : 아주 느린 네트워크로 보면 아주 천천히 다 받아서 아주 느린 흰 화면에서부터 하나하나 요청해서 채워나가는 부분이 있음. 브라우저가 js 코드가 있을 때만 ui를 만들 수 있음
server side render : 아주 느린 네트워크로 보면 바로 만들어짐 그런 차이가 있음
흰 화면이 보이는 부분이 문제가 되는 경우가 많음. 로딩중이라는 그 화면을 안 보여주는 문제가 있음
disable js 로 nextjs를 실행 전혀 차이가 없음. 실제로 html이 나오기 때문에 로딩 과정은 오래 걸릴 수 있어도 어떤 html은 볼 수 있기에 일단 흰 화면은 안 뜸
next.js는 component를 렌더링 하고, 그 결과를 소스코드에 넣어서 준다. 그리고 그것에 리엑트 js를 새로 붙힌다
js가 없어도 일단 html자체는 볼 수는 있음
Link tag는 href만을 위한 것, a 태그에 다 붙히는 걸로 생각하기
style 적용은 inline도 가능은 하지만
.module.css 패턴
<nav className={styles.nav}>
이 부분이 조금 특이함.
모듈로 처리하기에 그냥 className="nav"로 적어도 작동하지 않음. 그냥 충돌을 막는 효과
className={`${styles.link} ${
router.pathname === "/about" ? styles.active : ""
}`}
//혹은
className=[styles.link,router.pathname === "/about" ? styles.active : ""].join(" ")
이런 식으로 보통 처리하게 됨
styled component느낌
<style jsx>{`
nav {
background-color: tomato;
}
a {
text-decoration: none;
}
`}</style>
이렇게 되어 있는 경우에는 그 페이지에 있는 모든 것들에 다 적용이 됨. 다른 페이지는 영향을 끼치지 못함
조금 특이한 점은 className을 {"classname"} 같은 부분으로 추가하는 윗 부분에 적은 그 이름을 밑에 .classname으로 추가해도 변하지 않음
클래스 명을 페이지 단위로 관리해주는 듯?
a{
color:${props.color}
}
같은 것들도 가능
style jsx global 까지 붙히면 문제가 없이 되긴 함
page별로 고려해야 한다는 문제가 됨
이 부분은 한 페이지 단위로 글로벌 css가 됨.
그래서 이거를 전부 다 붙혀넣기 가능은 하지만 추천 하지 않음
App Component, App page
global css를 위한 장소가 있음 App component
_app.js 파일임
<style jsx global></style>
이렇게 된 것을 _app.js안에 넣는 방식으로 모든 문제가 해결됨
page 안에 있는 것들(_app제외) 에서는 무조건 모든 것들을 그냥 "../styles/glolbal" 불가능
app에서는 module.css만 불러낼 수 있음
_app에서만 import가능. 이러면 자동 적용
그냥은 현재 딱 보이는 컴포넌트에서만 작동함
다른 컴포넌트를 불러오는 경우 못 함
global 이 붙으면 한 페이지 단위
_app안에 넣으면 모든 페이지 단위
그냥 비슷하게 useeffect로 데이터 fetch가능
request에 mask를 씌우는 방법. request를 보는 것 만으로 apikey를 찾을 수 없도록 하는 것들
nextjs는 config부분이 있음
const API_KEY = process.env.API_KEY;
module.exports = {
reactStrictMode: true,
}
async redirects() {
return [
{
source: "/old-blog/:path*",
destination: "/new-sexy-blog/:path*",
permanent: false,
},
];
},
async rewrites() {
return [
{
source: "/api/movies",
destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`,
},
];
},
};
이 부분이 되게 신기함
source에 도달했을 경우 destination으로 보내줌
permanent: false
이때는 restart server를 해야 함
destination:"https://google.com" 도 가능함
pattern matching도 지원함.
*
부분이 모든 부분 뒤를 다 해결해준다는 것
rerwrite 는redirect를 해주기는 하지만, 내부에서 어떤 식으로 진행되는지 알 수가 없도록 숨겨줌
/api/movies에 fetch를 날리면 next에서 자동으로 destination으로 목적지를 바꿔줌
신기...
단 쿼리나 parameter에 섞일 가능성이 있는 경우 EncodeURIComponent로 그 부분 감싸는거 잊지 말기
이 부분은 서버에서 돌아감.
이러면 서버에서 알아서 다 한 다음에 완벽한 처리를 다 한 이후에 그 데이터를 보내는 것으로 처리를 함.
시간은 조금 더 걸릴 수 있겠지만 완벽한 apikey 숨기기가 가능함
import Seo from "../components/Seo";
import { GetServerSideProps, InferGetServerSidePropsType } from "next";
interface IMovieProps {
id: number;
backdrop_path: string;
original_title: string;
overview: string;
poster_path: string;
title: string;
vote_average: number;
genre_ids: [number];
}
function Home({ results }: InferGetServerSidePropsType<GetServerSideProps>) {
return (
<div className="container">
<Seo title="Home" />
{results?.map((movie: IMovieProps) => (
<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 {
cursor: pointer;
}
.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>
);
``;
}
/* export const getServerSideProps: GetServerSideProps = async () => {
...
}; */
export async function getServerSideProps({}: GetServerSideProps) {
const { results } = await (
await fetch(`http://localhost:3000/api/movies`)
).json();
return {
props: {
results,
},
};
}
export default Home;
index page에 대한 것들인데
볼 거는 꽤 있는 듯
server side
[name] 이라는 파일 명을 이용해 적는 방법이 있음
이런 방법으로 처리도 가능함
/:name임
그 path는 router을 통해서 판단하는 것
const router = useRouter();
이 느낌임
근데 query로 적힌다? 는 독특한 점이 있음
신기하다...
router hook을 사용한다.
onClick={()=>onClick=(movie.id)}
이렇게 받는데,
router.push(movies/${id}
) 딱 이느낌으로 처리되긴 함
대충 감은 잡을 수 있음
react-router-dom과 비슷함.
내부 url에서는 이거를 쓰고, 외부 url부분은 window.location쪽이 조금 더 적절하다고 함
push를 할 때 선택지가 있음. string도 가능하지만, 객체도 가능함
router.push({
pathname:'asdf',
query:{
id:'asdfasdf'
}
},"what brouser can see")
이런 방식으로 실제와 다른 경로를 보게 만들 수도 있음
catch all 부분 : 없는 404페이지
https://github.com/FIN443/next-simple-movie-app/blob/main/pages/index.tsx
ts 코드는 요쪽으로 가면 된다