Next.js의 페이지 라우터는 page 폴더의 구조를 기반으로 한 라우팅 방식으로써, React Router 처럼 페이지의 라우팅기능을 제공한다.
src
_app.tsx
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>
);
}
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.tsx 를 통해 앱 전체에 적용되는 공통적인 레이아웃을 적용보자.
Main
태그안에 {children}
으로 들어갈 수 있도록 한다.<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
을 만들고 이를 페이지별로 적용시켜보자
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>
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.tsx
의 Home 컴포넌트
가 전달되며 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>
}