Routing
Router
:을 사용해주어야 한다.[]로 감싸주면 된다.🤔 만약
pages와src/pages폴더가 모두 존재한다면?
pages 폴더에 작성한 코드가 우선적으로 적용된다.src/pages 폴더 내부의 코드는 무시된다.👩🏫 Next.js에서 생성한 페이지 파일은 어떻게 라우팅 될까요?pages/about.jspages/index.js ➡️ /pages/posts/index.js ➡️ /postspages/posts/firstPost.js ➡️ /posts/firstPostpages/board/user/userId.js ➡️ /board/user/userId/posts/[postId].js/posts/postId로 설정하는 대신 postId를 placeholder로 인식하고, 해당 컴포넌트에 접근하여 여러 데이터를 불러올 수 있다.posts/list.js가 존재하는 상황에서 위의 동적 라우팅의 postId 값에 list를 넣을 경우 원래 존재하던 posts/list.js 파일로 이동한다.pages/[userId]/modifyInfo.js ➡️ /:userId/modifyInfo (/foo/modifyInfo)pages/board/[slug].js ➡️ /board/:slug (board/firstPost)pages/posts/[...all].js ➡️ /posts/* (/posts/2023/title/user)👩🏫 위와 같은 라우팅을 구현하기 위해서는 어떤 방식을 사용해야 할까요?next/link👩🏫 페이지를 완전히 새로고침하므로 아래의 <Link> 태그를 사용하는 것이 좋습니다!👩🏫 Next.js는 Link 컴포넌트를 "Client-Side Navigation"이라고 설명합니다.Client-Side Navigation
Code Splitting
href (필수)
// 사전 정의된 경로: /about?name=test
<Link
          href={{
            pathname: '/about',
            query: { name: 'test' },
          }}
        >
// 동적 경로: /blog/my-post
<Link
    href={{
        pathname: '/blog/[slug]',
        query: { slug: 'my-post' },
    }}
>as
passHref
prefetch
prefetch={false} 전달 시 비활성화시킬 수 있다.replace
scroll
shallow
getStaticProps, getServerSideProps, getInitialProps를 실행하지 않고 현재 페이지의 경로만을 업데이트한다.locale
useRouter와 withRouter가 반환하는 값이다.pathname (string)
/pages 뒤에 오는 파일명을 의미한다.query (object)
asPath (string)
isFallback (boolean)
basePath (string)
next.config.js에서 설정할 수 있다.module.exports = {
  basePath: "/docs",
};/docs가 붙게 된다./user ➡️ /docs/userlocale (string)
locales (string[])
isReady (boolean)
isPreview (boolean)
next/router : useRouterimport { useRouter } from "next/router";
export default function Home() {
  const router = useRouter();
}router 객체에 접근할 수 있게 해주는 훅 함수useLocation, useHistory의 기능을 떠올리면 이해하기 쉽다.useHistory (useNavigate)의 기능과 유사하다.router.push(url, as, options);url (필수!)
<button
  type="button"
  onClick={() => {
    router.push({
      pathname: "/post/[pid]",
      query: { pid: post.id },
    });
  }}
>
  Click me
</button>as
options
| Option | type | 기본값 | 설명 | 
|---|---|---|---|
| scroll | boolean | true | 페이지 이동 후 상단 스크롤 | 
| shallow | boolean | false | getStaticProps, getServerSideProps, getInitialProps 실행 없이 현재 페이지 경로 업데이트 | 
| locale | string | 새 페이지의 locale | 
⚠️ 외부 URL로의 이동 시 router.push 보다 window.location을 사용하는 것이 더 적합하다!router.replace(url, as, options)<button type="button" onClick={() => router.replace("/home")}>
  Click me
</button>next/link가 없는 탐색에서 유용한 기능이다.router.prefetch(url, as);const handleSubmit = useCallback((e) => {
  e.preventDefault();
  fetch("/api/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({}),
  }).then((res) => {
    if (res.ok) router.push("/dashboard");
  });
}, []);
useEffect(() => {
  // Prefetch the dashboard page
  router.prefetch("/dashboard");
}, []);router.beforePopState(callbackFunc);useEffect(() => {
  router.beforePopState(({ url, as, options }) => {
    // 오직 아래의 두 경로만 허용하고 싶을 때
    if (as !== "/" && as !== "/other") {
      // 다른 주소인 경우 SSR 렌더링이 404 상태를 갖게 한다.
      window.location.href = as;
      return false;
    }
    return true;
  });
}, []);<button type="button" onClick={() => router.back()}>
  Click here to go back
</button>window.history.back()을 실행한다.<button type="button" onClick={() => router.reload()}>
  Click here to reload the page
</button>window.history.reload()을 실행한다.
reouteChangeStart(url, {shallow})
useEffect(() => {
  // 이벤트 구독
  const handleRouteChange = (url, { shallow }) => {
    console.log(
      `App is changing to ${url} ${
        shallow ? "with" : "without"
      } shallow routing`
    );
  };
  router.events.on("routeChangeStart", handleRouteChange);
  // 컴포넌트가 마운트되지 않은 경우 off 메서드로 구독을 취소한다.
  return () => {
    router.events.off("routeChangeStart", handleRouteChange);
  };
}, []);
routeChangeComplente(url, {shallow})
routeChangeError(err, url, {shallow})
useEffect(() => {
  const handleRouteChangeError = (err, url) => {
    if (err.cancelled) {
      console.log(`Route to ${url} was cancelled!`);
    }
  };
  router.events.on("routeChangeError", handleRouteChangeError);
  // 컴포넌트가 언마운트 되면 구독을 취소한다.
  return () => {
    router.events.off("routeChangeError", handleRouteChangeError);
  };
}, []);
beforeHistoryChange(url, {shallow})
hashChangeStart(url, {shallow})
hashChangeComplete(url, {shallow})
👩🏫
useRouter은 React Hook이므로 클래스 컴포넌트에서는 사용이 불가능합니다.
그렇다면 클래스 컴포넌트에서는 어떻게 router 객체에 접근할 수 있을까요?next/router : withRouterimport { withRouter } from "next/router";
function Page({ router }) {
  return <p>{router.pathname}</p>;
}
export default withRouter(Page);[slug] 부분에 query 값을 담아 보내면 params로 전달된다.⚠️ 주의할 점
🤠 as props를 추가해서 문제를 방지해줍시다!
import Link from "next/link";
function Home() {
  return (
    <ul>
      <li>
        <Link
          // /about?name=test
          href={{
            pathname: "/about",
            query: { name: "test" },
          }}
          as={`/about/question/${post.name}`}
        >
          <a>About us</a>
        </Link>
      </li>
      <li>
        <Link
          // /blog/my-post
          href={{
            pathname: "/blog/[slug]",
            query: { slug: "my-post" },
          }}
        >
          <a>Blog Post</a>
        </Link>
      </li>
    </ul>
  );
}
export default Home;[slug] 부분에 query 값을 담아 보내면 params로 전달된다.import { useRouter } from "next/router";
export default function ReadMore({ post }) {
  const router = useRouter();
  return (
    <button
      type="button"
      onClick={() => {
        router.push(
          {
            pathname: "/post/[pid]",
            query: { pid: post.id },
          },
          "/order"
        );
      }}
    >
      Click here to read more
    </button>
  );
}query 키 값을 사용하면 URL으로 전송된 query 데이터를 받아올 수 있다.import { useRouter } from 'next/router'
export default () => {
    const router = useRouter()
    const {pid} = router.query
    ...
}
useSearchParams로 query-string 받아오기// client-component에서 사용할 수 있다.
"use client";
import { useSearchParams } from "next/navigation";
export default function SearchBar() {
  const searchParams = useSearchParams();
  const search = searchParams.get("search");
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>;
}
URLSearchParams.get(searchParameter)
URLSearchParams.has(searchParameter)
page 컴포넌트에서 params, query-string 받아오기// app/blog/[slug]/page.tsx
export default function Page({
  params,
  searchParams,
}: {
  params: { slug: string }
  searchParams: { [key: string]: string | string[] | undefined }
}) {
  return <h1>My Page</h1>
}page의 props를 사용하여 params와 query-string을 받아올 수 있다.params (optional)
| 예시 | URL | params | 
|---|---|---|
| app/post-list/[slug]/page.js | /post-list/1 | { slug: '1' } | 
| app/post-list/[user]/[date]/post.js | /post-list/Jane/0822/1 | { user: "Jane", date: "0822" } | 
| app/post-list/[...slug]/page.js | /post-list/1/2/3 | { slug: ['1', '2', '3'] } | 
searchParams (optional)
| URL | searchParams | 
|---|---|
| /post?user=Jane | {user: "Jane"} | 
| /post?user=Jane&date=0822 | {user: "Jane", date: "0822"} | 
| /post?id=1&id=2 | {id: ["1", "2"]} |