Next.js 페이지 라우터 / 레이아웃 설정하기

이정수·2024년 9월 15일
0

NEXT

목록 보기
7/7

Page Router

Next.js의 페이지 라우터는 page 폴더의 구조를 기반으로 한 라우팅 방식으로써, React Router 처럼 페이지의 라우팅기능을 제공한다.

폴더구조

src

  • pages
    • api
    • _app.tsx
      페이지의 역할은 하지 않으나, Next 앱의 모든 페이지에 공통적으로 적용될 로직이나 레이아웃, 데이터를 다루기 위해 필요한 파일.
      리액트의 App 컴포넌트의 역할로, 모든 페이지 역할을 하는 컴포넌트의 부모 컴포넌트(루트)의 역할을 한다.
      export default function App({ Component, pageProps }: AppProps) {
        return <Component {...pageProps} />;
      }
      • Component 프롭 : 페이지의 역할을 할 컴포넌트를 받음
      • pageProps 프롭 : Component 프롭의 프롭역할을 할 객체를 모두 보관한것
    • _document.tsx 모든페이지의 공통적으로 적용되어야 하는 Next앱의 HTML코드를 설정하는 파일 기존 리액트앱의 index.html 파일과 비슷한 역할을 한다. 메타태그 설정, 폰트 불러오기, 캐릭터셋 설정, 구글 애널리틱스와 같은 서드파티 스크립트를 넣는 등 페이지 전체에 적용되는 HTML 태그를 관리하기 위함
      export default function Document() {
        return (
          <Html lang="en">
            <Head />
            <body>
              <Main />
              <NextScript />
            </body>
          </Html>
        );
      }
    • index.tsx

Global Layout 설정하기

CSS module 사용하기

next에서는css 파일을 임포트해서 사용하려면 파일명을 ~.module.css로 작성해야 한다.
이후, 임포트하여 사용할 경우에는 style 이라는 키워드로 가져온 후, 적용하고자 하는 요소에 className속성으로 적용한다.

//CSS module
import style from './index.module.css'

export default function Home() {
return <h1 className={style.h1}>index</h1>
}

index.module.css 파일

.h1 {
  color: red;
}

global layout

global-layout.tsx 를 통해 앱 전체에 적용되는 공통적인 레이아웃을 적용보자.

  • 헤더, 푸터가 여기에 속한다.
  • 페이지별로 달라지는 컨텐츠들은 Main태그안에 {children} 으로 들어갈 수 있도록 한다.
  • 루트 컴포넌트인 app.tsx를 <GlobalLayout>컴포넌트로 감싸서 모든 페이지에 적용될 수 있도록 한다.
export default function App({ Component, pageProps }: AppProps) {
  return (
    <GlobalLayout>
      <Component {...pageProps} />
    </GlobalLayout>
  )
}

src 폴더 아래에 components 폴더를 만들고, 그 안에 globla-layout.tsx 파일을 만든다.

import style from './global-layout.module.css'
export default function GlobalLayout({ children }: { children: ReactNode }) {
  return (
    <div className={style.container}>
      <header className={style.header}>
        <Link href={'/'}> 📚 Bite Books </Link>
      </header>
      <main className={style.main}>{children}</main>
      <footer className={style.footer}> 제작 @Jade</footer>
    </div>
  )
}

global-layout.tsx파일과 같은 위치에 global-layout.module.css 파일을 만든다.

.container {
  background-color: white;
  max-width: 600px;
  min-height: 100vh;
  margin: 0 auto;
  box-shadow: rgba(100, 100, 100, 0.2) 0px 0px 29px 0px;
  padding: 0px 15px;
}

.header {
  height: 60px;
  font-weight: bold;
  font-size: 18px;
  line-height: 60px;
}

...

페이지 별 레이아웃 설정

이번에 구현해볼 기능은, 페이지별로 특정 레이아웃이 적용되거나/적용되지 않도록 하는 것이다.

이 앱에서는 서치바가 들어간 페이지( /search, /index)와 서치바가 없는 페이지(/book/id)가 구분되어 있다.

SearchableLayout 을 만들고 이를 페이지별로 적용시켜보자

  1. seachable-layout.tsx
export default function SearchableLayout({
  children,
}: {
  children: ReactNode
}) {
  return (
    <div>
      <div>
        <input placeholder="검색어를 입력해주세요..." />
        <button> 검색 </button>
      </div>
      {children}
    </div>
  )
}

레이아웃에 서치바(인풋창,검색)를 추가해주고 나머지 컨텐츠는 children으로 받아서 아래에 위치시킨다.

❌ SearchableLayout 을 GlobalLayout처럼 app컴포넌트에 중첩시킨다면 모든 페이지에 보여지기 때문에 문제를 해결할 수 없다.

<GlobalLayout>
	<SearchableLayout>
		 <Component {...pageprops} />
	</SearchableLayout>
</GlobalLayout>
  1. SearchableLayout이 적용되길 원하는 페이지에 직접 추가해준다.

[ index.tsx ]

Home.**getLayout** = (page: ReactNode) => {
  return <SearchableLayout>{page}</SearchableLayout>
}
✅ Home컴포넌트에 `getLayout` 메소드를 추가한다.

getLayout 메소드는 페이지 컴포넌트를 받아서 searchable Layout을 감싼 형태로 리턴해준다.

→ 🖍️ 즉 어떤 페이지를 받아와서 레이아웃이 적용된 형태를 반환하도록 한다.

?? 이게 어떤 문법??

여기서 Home 은 export default function Home(){} 으로 정의된 함수이다. 그리고 Javascript에서 모든 함수는 객체이다.

때문에 레이아웃이 적용되길 원하는 컴포넌트에 메소드도 추가할 수 있다.

Anyway..

이제 사용자가 index페이지로 접속요청을 보내면 → Next앱의 App컴포넌트가 실행이 된다. → Component라는 이름의 props로 index.tsxHome 컴포넌트가 전달되며 getLayout이라는 메소드도 함께 전달된다. →

App 컴포넌트 내부에서는 Component.getLayout 으로 메소드를 꺼내와서 사용을 할 수 있다.

type NextPageWithLayout = NextPage & {
  getLayout?: (page: ReactNode) => ReactNode
}

export default function App({ Component, pageProps,}: 
  AppProps & { Component: NextPageWithLayout }) {
  
  const getLayout = 
	  Component.getLayout ?? ((page: ReactNode) => page)
  
  return 
	  <GlobalLayout>
		  {getLayout(<Component {...pageProps} />)}
	  </GlobalLayout>
}
profile
keep on pushing

0개의 댓글