[Nextjs] Layout (레이아웃)

김채운·2024년 1월 10일
1

Next.js

목록 보기
3/4

➡️ layout.js

layout은 페이지간에(routes) 공유가 가능한 UI이다. 그래서 layout.js파일은 여러 페이지(page.js)들에 공통적으로 적용되는 UI를 정의하는 컴포넌트라고 할 수 있다. layout.js는 하위의 page.js 및 layout.js 를 자식(children)으로 감싸서 화면을 렌더링 한다. 따라서 여러 레이아웃을 만들어 두고, 부모-자식 레이아웃 구조로 중첩하여 적용하는 방식도 가능하다.
이 layout파일은 어느 폴더든 만들고 싶은 곳에 만들 수 있고 폴더 안에 있는 자식 폴더에서도 공유가 가능하다.
또한 레이아웃(Layout)에 정의된 UI와 상태 값들은, (경로 이동-Navigation 등이 발생하더라도) 계속해서 유지되며 재렌더링 되지 않고 재활용된다.
보통 header,navbar,footer등 어느 페이지건 변하지 않고 공통적이고 고정적으로 들어가는 부분을 layout으로 만들어둔다.

➡️ Root Layout

Next프로젝트를 생성하면 기본적으로 app폴더 안에 layout파일이 생성되는데 이 파일이 루트 레이아웃이다. /app 디렉토리의 최상위에 있는 layout.js파일로, 모든 route경로에 적용이 된다. 이 말은 /app경로에 있는 폴더 그리고 그 폴더의 자식 폴더에 정의된 모든 page.js나 layout.js 컴포넌트들은 루트 레이아웃의 자식이 되어서 렌더링이 된다는 뜻이다.
루트 레이아웃은 app디렉토리의 최상위 레이아웃으로 html과 body태그를 반드시 포함해야 한다.

/app 디렉토리는 반드시 루트 레이아웃(layout.js)을 포함해야 한다.

다른 중첩 폴더에 layout.js가 있더라도, 반드시 /app 최상위 레벨에 루트 layout.js 파일이 존재해야 한다.
필요에 따라 (Route Group)으로 구분하여 정의할 수도 있다.

<html><body> 태그를 포함해야 한다.

오직 루트 레이아웃만 이 태그들을 포함할 수 있다.
다른 하위의 레이아웃은 이 태그들을 포함할 수 없다.

반드시 Server Component여야 한다.

루트 레이아웃은 Client Component로 전환해선 안 된다.
루트 레이아웃을 제외한 하위의 다른 레이아웃들은 Client Component로 전환할 수 있다.

➡️ layout.js 파라미터

children (required)

  • 레이아웃 컴포넌트는 "children" 프로퍼티를 필수로 받아 사용해야 한다. 이 프로퍼티에는 레이아웃이 감싸고 있는 페이지 컴포넌트의 내용이 전달된다.
  • 이 children 프로퍼티를 통해 페이지의 컴포넌트가 레이아웃에 포함되고, 페이지의 경로 세그먼트도 함께 전달된다.
  • 레이아웃이 어떤 페이지를 감싸는 역할을 할 때, "children"은 해당 페이지의 컴포넌트가 된다. 이는 주로 자식 레이아웃(만약 존재한다면) 또는 페이지 컴포넌트일 것이다.
  • 레이아웃이 특별한 파일(예: Loading 또는 Error)을 감싸고 있을 때, "children"은 해당 특별한 파일의 컴포넌트가 될 수 있다.
// layouts/MainLayout.js
const MainLayout = ({ children }) => {
  return (
    <div>
      <header>Header</header>
      <main>{children}</main>
      <footer>Footer</footer>
    </div>
  );
};

export default MainLayout;
// pages/index.js
import MainLayout from '../layouts/MainLayout';

const HomePage = () => {
  return (
    <MainLayout>
      <h1>Welcome to the Home Page</h1>
    </MainLayout>
  );
};

export default HomePage;

여기서 MainLayout컴포넌트의 "children" 프로퍼티는 h1태그의 Welcome to the Home Page가 된다. 따라서 레이아웃은 이 내용을 감싸고 다양한 페이지에 동일한 레이아웃을 적용할 수 있게 된다.

params (optional)

  • 레이아웃 컴포넌트는 params라는 프로퍼티를 받을 수 있다. 이 프로퍼티에는 동적 경로(dynamic route)에서 추출한 파라미터 값이 포함된다.
  • 동적 경로에서는 일반적으로 대괄호([])로 둘러싸인 부분을 파라미터로 정의한다. 예를 들어, "/blog/[slug]" 경로에서 "[slug]"는 동적인 부분이며, 실제 브라우저의 주소에서 이 부분에 해당하는 값이 params로 전달된다.
// app/shop/[tag]/[item]/layout.tsx
export default function ShopLayout({
  children,
  params,
}: {
  children: React.ReactNode
  params: {
    tag: string
    item: string
  }
}) {
  // URL -> /shop/shoes/nike-air-max-97
  // `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
  return <section>{children}</section>
}

이를 통해 레이아웃 컴포넌트에서 동적 경로에서 추출한 파라미터 값을 활용할 수 있다.

➡️ searchParams

알아두어야 할 내용으로 Layout 컴포넌트는 searchParams 프로퍼티를 받지 않는다는 것이다. 이는 페이지 간의 네비게이션에서 레이아웃 컴포넌트가 어떻게 동작하는지에 대해 알 수 있다.

Layout do not receive searchParams

  • 레이아웃 컴포넌트는 'searchParams' 프로퍼티를 받지 않는데, 이유는 레이아웃이 네비게이션 중에 다시 렌더링되지 않기 때문이다.
  • 페이지 간에 공유되는 레이아웃은 네비게이션 도중에 다시 렌더링 되지 않는다. 이는 네비게이션 중에 공유된 레이아웃에서 발생할 수 있는 'searchParams'의 상태 불일치 문제를 방지하기 위한 것이다.

Client Side Navigation Optimization

  • 클라이언트 측에서의 네비게이션 시, Nextjs는 공통된 레이아웃 아래의 페이지 일부만 다시 렌더링한다. ex) dashboard/layout.tsx이 공통 레이아웃이라 할 때 "/dashboard/settings"에서 "/dashboard/analytics"로 이동한다 하면, dashboard/layout.tsx는 서버에서 다시 렌더링되지 않는다.
  • 이러한 성능 최적화로인해 공유된 레이아웃을 가진 페이지 간의 네비게이션은 더 빠르다. 전체 route를 다시 렌더링할 필요 없이 해당 페이지의 데이터 가져오기와 렌더링만 실행하기 때문이다.

searchParams in Layout Server Component

  • dashboard/layout.tsx가 다시 렌더링되지 않기 때문에 레이아웃 서버 컴포넌트 내의 searchParams 프로퍼티는 네비게이션 이후에 불일치할 수 있다.
  • 대신에 page의 'searchParams'프로퍼티나 클라이언트 컴포넌트에서 'useSearchParams' hook을 사용해 클라이언트에서 최신 'searchParams'로 다시 렌더링되는 컴포넌트에서 사용할 수 있다.

이를 통해 결과적으로 공통된 레이아웃을 가진 페이지 간의 네비게이션이 더욱 효율적으로 처리되며, 레이아웃이 네비게이션 중에 다시 렌더링되지 않아도 되기 때문에 성능이 향상된다.

출처

0개의 댓글