레이아웃 컴포넌트
레이아웃(layout) 컴포넌트는 페이지 라우터에서 자주 쓰이는 컴포넌트이자 페이지 구성 패턴입니다. 넥스트에서 레이아웃 컴포넌트는 /layouts
폴더 밑에 위치한 컴포넌트를 가리킵니다.
레이아웃 컴포넌트 목적
여러 페이지에 페이지 헤더가 존재하는 웹 애플리케이션이 있다고 해보겠습니다. 이 애플리케이션은 메인 페이지와 로그인 페이지로 구성되어 있습니다. 이때 두 페이지 모두 상단에 페이지 헤더를 다음과 같이 나타낸다고 해봅시다.
<!-- 로그인 페이지 -->
<h1>나의 앱</h1>
<main>
<form>
<label>로그인 아이디</label>
<input/>
</form>
</main>
<!-- 메인 페이지 -->
<h1>나의 앱</h1>
<main>
<section>메인</section>
</main>
이 두 페이지는 모두 헤더 역할을 하는 <h1>나의 앱</h1>
코드를 공통으로 정의하고 있습니다. 넥스트에서는 이렇게 페이지마다 공통으로 들어가는 요소를 레이아웃 컴포넌트에 정의하여 코드의 중복을 방지합니다.
export default function Layout({ children }) {
return (
<>
<h1>나의 앱</h1>
<div>{children}</div>
</>
)
}
위 코드에서 <> </>
문법은 프라그먼트(Fragment) 문법을 의미합니다. 리액트 컴포넌트는 화면에 표시할 UI가 최상위 엘리먼트(HTML 요소)를 1개만 갖고 있어야 합니다. 이런 제약사항 때문에 여러 개의 엘리먼트를 최상위 엘리먼트에 배치하고 싶을 때 프라그먼트를 사용합니다. 프라그먼트는 실제로 화면에 그려지는 엘리먼트는 아니고 논리적으로만 최상위 태그가 있는 것처럼 보이게 만드는 효과를 갖습니다.
레이아웃 컴포넌트 기본
이렇게 생성한 레이아웃 파일은 _app.jsx
파일에서 다음과 같이 사용합니다.
import Layout from '../layouts/Layout'
export default function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
레이아웃 컴포넌트를 구성하게 되면 페이지를 이동해도 <Component>
영역만 변하게 되기 때문에 레이아웃 컴포넌트 내부의 상태는 보존됩니다.
레이아웃 컴포넌트 응용
만약 구현하려는 웹 애플리케이션에서 UI 레이아웃이 다 달라 여러 개의 레이아웃 컴포넌트를 사용해야 한다면 어떻게 해야 할까요? 그럴땐 아래와 같이 Per-Page 레이아웃 방식을 이용합니다.
import SimpleLayout from '../layouts/SimpleLayout'
export default function LoginPage() {
return <div>로그인</div>
}
LoginPage.getLayout = function getLayout(page) {
return (
<SimpleLayout>{page}</SimpleLayout>
)
}
import AdminLayout from '../layouts/AdminLayout'
export default function MainPage() {
return <div>메인</div>
}
MainPage.getLayout = function getLayout(page) {
return (
<AdminLayout>{page}</AdminLayout>
)
}
export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout ?? ((page) => page)
return getLayout(<Component {...pageProps} />)
}
레이아웃 컴포넌트에서 데이터 호출하기
만약 레이아웃 컴포넌트에서 서버 데이터를 호출하고 싶다면 useEffect
나 SWR
과 같은 클라이언트의 데이터 호출 방식을 사용해야 합니다. 왜냐하면 레이아웃 컴포넌트는 페이지 컴포넌트가 아니기 때문에 getStaticProps
, getServerSideProps
과 같은 서버 사이드 데이터 호출 속성이 지원되지 않기 때문입니다.