React 모델을 사용하면 페이지를 일련의 컴포넌트로 분해할 수 있다. 이러한 컴포넌트 중 다수는 종종 페이지간에 재사용된다. 예를 들어 모든 페이지에 동일한 탐색 모음과 바닥글이 있을 수 있다.
// components/layout.js
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
return (
<>
<Navbar />
<main>{children}</main>
<Footer />
</>
)
}
- 커스텀 앱의 단일 공유 레이아웃
전체 앱에 대해 하나의 레이아웃만 있는 경우 사용자 지정 앱을 생성하고 해당 레이아웃으로 앱을 래핑 할 수 있다. 페이지를 변경할 때 <Layout /> 컴포넌트가 재사용되기 때문에 해당 컴포넌트의 상태(예: 입력 값)가 보존된다.
// pages/_app.js
import Layout from '../components/layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
- 페이지 별 레이아웃
여러 레이아웃이 필요한 경우 페이지에 getLayout 속성을 추가하여 레이아웃에 대한 React 컴포넌트를 반환할 수 있다. 이렇게 하면 페이지별로 레이아웃을 정의할 수 있다. 함수를 반환하기 때문에 원하는 경우 복잡한 중첩 레이아웃을 가질 수도 있다.
// pages/index.js
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
export default function Page() {
return (
// ...content
)
}
Page.getLayout = function getLayout(page) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
// pages/_app.js
export default function MyApp({ Component, pageProps }) {
// 가능한 경우 페이지 레벨에서 정의된 레이아웃을 사용한다.
const getLayout = component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
페이지 사이를 탐색할 때 SPA(Single-Page Application) 경험을 위해 페이지 상태(입력 값, 스크롤 위치 등)를 유지하려고 한다. 이 레이아웃 패턴은 React 컴포넌트 트리가 페이지 전환 간에 유지되기 때문에 상태 지속성을 가능하게 한다. 컴포넌트 트리를 통해 React는 상태를 유지하기 위해 어떤 요소가 변경되었는지 이해할 수 있다.
- TypeScript 사용
TypeScript를 사용할 때 먼저 getLayout 함수를 포함하는 페이지에 대한 새 type을 만들어야 한다. 그런 다음 이전에 만든 type을 사용하도록 Component 속성을 재정의하여 AppProps를 위한 새 type을 만들어야만 한다.
// pages/index.tsx
import type { ReactElement } from 'react';
import Layout from '../components/layout'
import NestedLayout from '../components/nested-layout'
import type { NextPageWithLayout } from './_app'
const Page: NextPageWithLayout = () => {
return <p>hello world</p>
}
Page.getLayout = function getLayout(page: ReactElement) {
return (
<Layout>
<NestedLayout>{page}</NestedLayout>
</Layout>
)
}
export default Page
// pages/_app.tsx
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode
}
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout
}
export default function MyApp({ Component, pageProps }: AppPropsWithLayout) {
const getLayout = Component.getLayout ?? ((page) => page)
return getLayout(<component {...pageProps} />)
}
- 데이터 가져오기
레이아웃 내에서 useEffect 또는 SWR과 같은 라이브러리를 사용하여 클라이언트 측에서 데이터를 가져올 수 있다. 물론 이 파일은 Page가 아니기 때문에 getStaticProps나 getServerSideProps를 지금까지는 사용할 수 없다.
// components/layout.js
import useSWR from 'swr'
import Navbar from './navbar'
import Footer from './footer'
export default function Layout({ children }) {
const { data, error } = useSWR(`/api/navigation`, fetcher)
if (error) return <div>Failed to load</div>
if (!data) return <div>Loading...</div>
return (
<>
<Navbar links={data.links} />
<main>{children}</main>
<Footer />
</>
)
}
'Next.js' 카테고리의 다른 글
Next.js 9-2. Image Component and Image Optimization (0) | 2023.04.28 |
---|---|
Next.js 9-1. Image-Component and Image Optimiztion (0) | 2023.04.28 |
Next.js 7. Built-in CSS Support (0) | 2023.04.27 |
Next.js 6. Client-side data fetching (0) | 2023.04.26 |
Next.js 5-2. ISR(Incremental Static Regeneration) (0) | 2023.04.25 |