Next 26장 - 기초부터 다시 배우기 v12 (3)
포스트
취소

Next 26장 - 기초부터 다시 배우기 v12 (3)

Next

  • v12를 기준으로 합니다.
  • 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를 컴포넌트에게 전달
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.