레이아웃
지원환경: React NativeReact Native SDKv1.0.3
실행환경: Toss AppSandbox App
레이아웃은 여러 페이지에서 반복되는 UI 요소(헤더, 네비게이션 바, 푸터 등)를 일관성 있게 관리하기 위한 구조예요.
공통 레이아웃을 정의하면 코드 중복을 줄이고, 일관된 사용자 경험을 제공할 수 있어요.
레이아웃 파일 만들기
레이아웃은 _layout.tsx 파일을 생성해서 정의해요.
파일의 위치에 따라 적용되는 범위가 달라져요.
tsx
import { PropsWithChildren } from "react";
export default function Layout({ children }: PropsWithChildren) {
return <>{children}</>;
}레이아웃 적용 범위 설정하기
레이아웃은 파일 경로에 따라 자동으로 적용돼요.
pages/_layout.tsx: 모든 페이지에 전역 적용돼요.pages/about/_layout.tsx:intoss://{서비스명}/about하위의 모든 페이지에만 적용돼요.

레이아웃은 중첩해서 사용할 수 있어요.
여러 레이아웃이 함께 있을 때는 상위 디렉토리의 레이아웃부터 순서대로 적용돼요.
pages/
├── _layout.tsx // 전역 레이아웃
├── about/
│ ├── _layout.tsx // about 섹션 레이아웃
│ ├── index.tsx // about 메인 페이지
│ └── team.tsx // 팀 소개 페이지
└── index.tsx // 메인 페이지예를 들어, 위와 같은 구조라면 about/team.tsx 페이지는 아래 순서로 레이아웃이 적용돼요.
pages/_layout.tsx(전역 레이아웃)pages/about/_layout.tsx(섹션 레이아웃)pages/about/team.tsx(실제 페이지 컴포넌트)
이렇게 구성하면 전역적으로 필요한 UI 요소와, 특정 섹션에서만 필요한 UI 요소를 분리해서 관리할 수 있어요.
레이아웃 예시
전역 레이아웃
모든 페이지에 공통으로 적용되는 레이아웃을 만들어볼게요.
tsx
import { PropsWithChildren } from "react";
import { View } from "react-native";
import { Header } from "../components/Header";
import { Footer } from "../components/Footer";
export default function Layout({ children }: PropsWithChildren) {
return (
<View style={{ flex: 1 }}>
<Header />
{children}
<Footer />
</View>
);
}tsx
import { View, Text, StyleSheet } from "react-native";
export function Header() {
return (
<View style={styles.header}>
<Text style={styles.title}>My App</Text>
<View style={styles.nav}>
<Text style={styles.navItem}>홈</Text>
<Text style={styles.navItem}>소개</Text>
<Text style={styles.navItem}>설정</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
header: {
padding: 16,
backgroundColor: "#ffffff",
borderBottomWidth: 1,
borderBottomColor: "#e5e5e5",
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 8,
},
nav: {
flexDirection: "row",
gap: 16,
},
navItem: {
fontSize: 16,
color: "#666666",
},
});tsx
import { View, Text, StyleSheet } from "react-native";
export function Footer() {
return (
<View style={styles.footer}>
<Text style={styles.copyright}>© 2024 My App. All rights reserved.</Text>
</View>
);
}
const styles = StyleSheet.create({
footer: {
padding: 16,
backgroundColor: "#f5f5f5",
alignItems: "center",
},
copyright: {
fontSize: 14,
color: "#666666",
},
});섹션별 레이아웃
특정 섹션에서만 사용하는 레이아웃을 만들 수 있어요.
tsx
import { PropsWithChildren } from "react";
import { View } from "react-native";
import { AboutSidebar } from "../../components/AboutSidebar";
export default function AboutLayout({ children }: PropsWithChildren) {
return (
<View style={{ flexDirection: "row" }}>
<AboutSidebar />
<View style={{ flex: 1 }}>{children}</View>
</View>
);
}tsx
import { View, Text, StyleSheet } from "react-native";
export function AboutSidebar() {
return (
<View style={styles.sidebar}>
<Text style={styles.title}>About</Text>
<View style={styles.menu}>
<Text style={styles.menuItem}>회사 소개</Text>
<Text style={styles.menuItem}>팀 소개</Text>
<Text style={styles.menuItem}>연혁</Text>
<Text style={styles.menuItem}>오시는 길</Text>
</View>
</View>
);
}
const styles = StyleSheet.create({
sidebar: {
width: 200,
padding: 16,
backgroundColor: "#f8f9fa",
borderRightWidth: 1,
borderRightColor: "#e5e5e5",
},
title: {
fontSize: 20,
fontWeight: "bold",
marginBottom: 16,
},
menu: {
gap: 12,
},
menuItem: {
fontSize: 16,
color: "#495057",
},
});레이아웃에서 쿼리 파라미터 받아오기
레이아웃에서도 쿼리 파라미터를 사용할 수 있어요.useParams 훅을 이용하면 현재 화면의 파라미터를 읽어서 동적으로 활용할 수 있어요.
useParams 훅 사용 예시
아래 예시는 URL 쿼리 파라미터로 전달된 title 값을 가져와서 화면 상단 제목으로 표시해요.
tsx
import { useParams } from "@granite-js/react-native";
import { PropsWithChildren } from "react";
import { View, Text } from "react-native";
export default function Layout({ children }: PropsWithChildren) {
// 현재 화면의 파라미터를 가져와요.
const params = useParams({ strict: false });
// 'title' 파라미터를 가져오고 기본값을 설정해요.
const title = params?.title ?? "기본 제목";
return (
<View style={{ flex: 1 }}>
{/* 동적으로 생성된 헤더 */}
<View style={{ padding: 16, backgroundColor: "#f0f0f0" }}>
<Text style={{ fontSize: 20, fontWeight: "bold" }}>{title}</Text>
</View>
{/* 자식 컴포넌트를 렌더링 */}
<View style={{ flex: 1 }}>{children}</View>
</View>
);
}