Next
- v12를 기준으로 합니다.
Head
- Next.js v14 에서는
Metadata
를 가져와 그대로 사용할 수 있었다. - v12에는 없기 때문에 import Head from “next/head”를 가져와서
metadata
를 작성하고, 동적 메타 데이터를 작성하는 방식과 유사하게, 일일이 작성하는 것이 아닌 동적으로 작성할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Seo.tsx
import Head from "next/head";
export default function Seo({title} : {title: string || ...}){
return (
<Head>
<title>{title} | Next.js</title>
<meta>...</meta>
</Head>
)
}
// home/index.tsx
export default function Home(){
return (
<Seo title="Home"/>
...
)
}
Redirect & Rewrite
- 공식문서
- 두 함수 모두 배열을 반환하기 떄문에 여러 객체를 추가하여 사용해도 된다.
1
2
3
4
5
6
7
8
9
10
11
...
async (redirects || rewrites)(){
return [
{
...
},
{
...
}
]
}
Redirect
- 사용자가 특정 URL로 이동했을 때, 어느 주소로 이동시켜줄 것을 설정할 수 있다.
next.config
파일에 async redirects 함수를 이용하여, 사용자가 이동하는 url인 source와 이동시켜 줄 url인 destination 을 사용하면 된다.- permanent의 옵션값을 사용하여 임시/영구 redirect (307,308 code)를 설정할 수 있다. 참고
- url에 붙는 path에 관해서도 redirect 설정을 할 수 있다.
*
을 이용해 모든 url을 그대로 가져올 수도 있다.- 파일 수정 후 서버 재시작은 필수이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// next.config.ts
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
async redirects() {
return [
{
source: "/cur-page",
destination: "/new-page",
permanent: false,
},
];
},
};
// path
...
{
source: "/cur-page/:path",
destination: "/new-page/:path",
...
}
// *
{
source: "/cur-page*",
destination: "/new-page*",
...
}
// http://.../cur-page/anywhere/123 => http://.../new-page/anywhere/123
module.exports = nextConfig;
Rewrite
Redirect
는 사용자의 URL를 우리가 원하는 URL로 옮겨주는 역할을 한다.- 이는 사용자에게 인식되는 것과 다르게 Rewrite는 사용자에게 노출되지 않게 URL을 마스킹 해주는 역할을 한다.
- 네트워크에서 API 키가 노출되지 않도록, API 키를 숨기는 것에 용이하다.
- 마찬가지로 async rewrites를 사용한다.
rewrites
로 숨겨준 URL은 사용자에게 노출되지 않으며, 네트워크 탭에서도 기존의 API가 포함된 요청이 아닌 source로 작성된 URL이 사용자에게 보여진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// next.config.js
{
...,
async rewrites(){
return [
{
source: "/api/movies", // 사용자에게 보여질 URL
destination: "api/movies&api=API_KEY", // 숨겨줄 URL
permanent: ...
}
]
}
}
// index.ts
export default function Home(){
const [movies, setMovies] = useState([]);
useEffect(() => {
(async () => {
const {results} = awiat (
// 기존 awiat fetch("http://.../api/movie&api=123")
// => rewrites 를 사용하여 api를 대체해주기 때문에 수정된 source url 사용 가능
awiat fetch("/api/movie")
// => 정상적으로 results를 받아온다.
).json();
setMovies();
})
},[])
return (
...
)
}
// http://.../api/movie&api=123 => http://.../api/movie
+추가 as 옵션 사용하기
- 페이지 이동 간에
router.push
를 이용하는 경우가 생긴다. - 예를 들어,
url
에 내가 클릭한 영화에 대한 제목과 평점 등의 정보를 포함하여 넘겨주려고 할 떄https://.../movie/detail?id=12345&title=example
처럼 모든 정보를url
에 담아두는 것은 좋지 않다. - 이럴 때 router의 as 옵션을 사용하여 router 안에 정보는 담고 url 자체는 숨겨줄 수 있다.
- next/Link 에서도 똑같이 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { useRouter } from "next/navigation";
export default function Example() {
const router = useRouter();
const onClick = (id: string, title: string) => {
router.push(
{
// pathname: `/movies/${id}`,
query: {
title: "example",
},
},
`/movies/${id}` // => push(, as) => as로 들어간 url로 보여진다.
);
};
return (
<Link
href={
{
// pathname: `/movies/${id}`,
// query: {
// title: "example",
// },
}
}
as={`/movies/${title}`}
></Link>
);
}
Server Side
- Next 공식문서
- 위
Rewrite
를 통해Home
에서 전송하는API KEY
를 숨겨줄 수도 있지만 server side props를 이용하여 SSR으로 실행하고, API KEY를 노출시키지 않을 수도 있다. - 또한
useState, useEffect
와 같은 훅을 사용하지 않아도 된다. - Next v14 부터 SSR을 위한
get~
은 사용하지 않기 때문에 v12,13을 기준으로 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 기존 코드
// index.tsx
export default function Home(){
const [movies, setMovies] = useState([]);
useEffect(() => {
(async () => {
const {results} = awiat (
// 기존 awiat fetch("http://.../api/movie&api=123")
// => rewrites 를 사용하여 api를 대체해주기 때문에 수정된 source url 사용 가능
awiat fetch("/api/movie")
// => 정상적으로 results를 받아온다.
).json();
setMovies();
})
},[])
return (
...
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// getServerSideProps
// index.tsx
import type { InferGetServerSidePropsType, GetServerSideProps } from 'next'
type Props = {
results: ResultsType,
}
export const getServerSideProps = (async () => {
const {results} = await (
await fetch("http://.../api/movie&api=123")
).json();
return {
props: {results}
}
}) satisfies GetServerSideProps<{ results: Props }>
export default function Home({results}:InferGetServerSidePropsType<typeof getServerSideProps>){
if(!results){<div>조회된 데이터가 없습니다.</div>}
return (
<ul>
{results.map(item => (
<li>{item.title}</li>
))}
</ul>
)
}
- Next.js가 사용된 getServerSideProps, getStaticProps ,getStaticPaths를 인식하여 SSR으로 동작하며, 서버에서 실행된 fetch를 통해 Home에게 Props로 전달된다.
- 서버에서 실행되기 떄문에 API KEY를 그대로 사용해도 사용자에게 노출되지 않는다.
- 주의, 위에서 사용한 Rewrite를 사용한 source URL로 그대로 사용할 수 없는데, 브라우저는 이미 URL을 갖고 있기 때문에 기존의 URL에 source URL만 붙여주면 되지만, 서버에는 URL이 없기 때문에 전체 URL을 모두 작성해주어야 한다.
1
2
3
4
5
// 기존
await fetch("/api/movies") => // Rewrite URL 사용
// getServerSideProps
await fetch("https://.../api/movies") => // 전체 URL 필요
+추가 Props
- getServerSideProps, … 등을 사용하여 받아온 Props를 컴포넌트에서 사용할 수 있는 것은 Next.js가 App 컴포넌트에서 …pageProps 로 컴포넌트에 전달해주기 떄문이다.
1
2
3
4
5
6
// _app.tsx
import type { AppProps } from "next/app";
export default function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />; // => pageProps로 미리 받아온 props를 컴포넌트에게 전달
}