React Native는 프로젝트의 디렉터리 구조를 강제하지 않음
프로젝트 규모 / 기능 / 팀 협업 방식에 따라 자유롭게 설계 가능
But) Expo Router를 사용하는 경우, 파일 기반 라우팅을 위해 특정 디렉터리 규칙을 따라야 함.
| 구분 | React (Vite) | React Native (Expo) |
|---|---|---|
| UI 구성 | HTML / CSS | View / Text / StyleSheet |
| 화면 이동 | React Router 등 | Expo Router / React Navigation 등 |
| 스타일 | CSS / Tailwind | StyleSheet 등 |
| 정적 파일 | public / src/assets | assets 등 |
| 폴더 구조 | 자유롭게 구성 | 기본적으로 자유롭게 구성 |
| 플랫폼 코드 | 주로 웹 | iOS / Android 구분 가능 |
▶ React Native도 React와 동일하게 컴포넌트·기능 중심 구조 사용 가능
: 파일의 역할 또는 종류를 기준으로 분리하는 방식
src/
├── components/
├── screens/
├── hooks/
├── services/
├── types/
└── utils/
components: UI 컴포넌트screens: 화면 단위 컴포넌트hooks: 커스텀 훅services: API 및 외부 서비스types: TypeScript 타입utils: 공용 유틸리티장점
단점
: 기능을 기준으로 관련 컴포넌트·로직·타입 등을 함께 관리하는 방식
src/
├── features/
│ ├── calendar/
│ │ ├── components/
│ │ ├── hooks/
│ │ └── types/
│ ├── event/
│ │ ├── components/
│ │ ├── hooks/
│ │ └── types/
│ └── settings/
│ ├── components/
│ └── hooks/
└── shared/
├── components/
├── hooks/
└── utils/
features: 기능별 코드shared: 여러 기능에서 재사용하는 공통 코드장점
단점
| 구분 | Type-based | Feature-based |
|---|---|---|
| 분리 기준 | 파일 종류 | 기능 |
| 초기 구조 | 단순 | 상대적으로 복잡 |
| 기능 확장 | 파일 분산 가능 | 기능별 관리 용이 |
| 공용 코드 | 최상위 폴더 | shared 등 별도 관리 |
| 적합한 프로젝트 | 소규모 / 프로토타입 | 기능이 많은 앱 / 협업 |
▶ Tryna는 기능별 화면이 구분되므로 Feature-based 구조를 우선 검토
Expo Router: Expo에서 제공하는 파일 기반 라우팅(File-based Routing) 라이브러리
파일과 디렉터리 구조를 기반으로 앱의 화면 경로를 정의
예를 들어:
src/
├── app/
│ ├── _layout.tsx
│ ├── index.tsx
│ ├── calendar.tsx
│ └── settings.tsx
index.tsx: 기본 경로 /calendar.tsx: /calendarsettings.tsx: /settings_layout.tsx: 공통 레이아웃 및 네비게이션 구성app/: 화면 경로를 정의하는 디렉터리index.tsx: 해당 디렉터리의 기본 화면 (App.tsx의 역할)_layout.tsx: 화면을 감싸는 레이아웃 및 네비게이터[id].tsx: 동적 경로(tabs)/: URL 경로에 포함되지 않는 Route Group예시:
src/
└── app/
├── _layout.tsx
├── index.tsx
├── (tabs)/
│ ├── _layout.tsx
│ ├── calendar.tsx
│ └── daily.tsx
└── event/
└── [id].tsx
event/[id].tsx → /event/123과 같은 동적 경로 표현 가능
주의) app/ 내부의 파일은 라우팅 대상으로 해석될 수 있으므로, 일반적인 공용 컴포넌트나 유틸리티는 외부에서 관리하는 것이 좋음.
→ app은 라우팅 / features는 기능 구현 / shared는 공용 코드
※ Expo Router를 사용하지 않고 React Navigation을 직접 구성하는 경우에는 app/ 파일 기반 라우팅 규칙이 필요하지 않음.
| 폴더 | 역할 |
|---|---|
app/ | Expo Router 화면 및 레이아웃 |
features/ | 기능별 컴포넌트 및 비즈니스 로직 |
components/ | 공용 UI 컴포넌트 |
hooks/ | 공용 커스텀 훅 |
theme/ | 색상·간격·타이포그래피 등 디자인 토큰 |
assets/ | 이미지·폰트 등 정적 리소스 |
services/ 또는 apis/ | API 통신 및 외부 서비스 |
types/ | 공용 TypeScript 타입 |
utils/ | 공용 유틸리티 함수 |
constants/ | 공용 상수 |
모든 폴더를 처음부터 생성할 필요는 없음.
→ 실제로 사용하는 기능에 맞춰 점진적으로 추가
React Native는 파일명에 플랫폼 확장자를 사용하여 코드를 구분할 수 있음.
components/
├── DatePicker.ios.tsx
├── DatePicker.android.tsx
└── DatePicker.tsx
.ios.tsx: iOS 전용 구현.android.tsx: Android 전용 구현.tsx: 플랫폼별 파일이 없는 경우 사용하는 공통 구현장점
But) 플랫폼별 차이가 없는 경우에는 파일을 분리할 필요 없음.
→ 공통 구현을 우선하고, 실제 플랫폼 차이가 발생할 때 분리
Tryna는 일정·할 일·설정 등 여러 기능을 제공하며, 공용 UI 컴포넌트를 재사용하는 구조
또한 기존 React 프로젝트에서 구현한 공용 컴포넌트를 React Native로 이식할 예정
→ Feature-based + Shared 구조 채택 검토
tryna/
├── assets/
│ ├── fonts/
│ └── images/
├── src/
│ ├── app/
│ │ ├── _layout.tsx
│ │ ├── index.tsx
│ │ ├── calendar/
│ │ ├── daily/
│ │ └── event/
│ ├── components/
│ │ ├── Todo/
│ │ ├── Button/
│ │ └── BottomSheet/
│ ├── features/
│ │ ├── calendar/
│ │ ├── daily/
│ │ └── event/
│ ├── theme/
│ │ ├── colors.ts
│ │ ├── spacing.ts
│ │ └── typography.ts
│ ├── hooks/
│ ├── apis/
│ ├── types/
│ └── utils/
├── app.json
├── eas.json
├── package.json
└── tsconfig.json
※ Expo Router 사용을 가정한 예시이며, 최종 디렉터리 구조는 아님.
1. 라우팅과 화면 구현 분리
app/: 경로 및 화면 연결features/: 실제 기능 및 화면 구현2. 공용 컴포넌트 관리
components/features/{기능}/components/3. TDS 디자인 토큰 관리
theme/: React Native용 TDS 토큰StyleSheet.create()에서 공통으로 참조4. 플랫폼별 코드 최소화
React Native는 단일 폴더 구조를 강제하지 않으며, 프로젝트 특성에 맞춰 설계 가능
▶ Tryna는 Feature-based 구조를 기반으로 공용 컴포넌트와 디자인 토큰을 별도 관리하는 방향 검토
▶ 폴더 구조 확정 → TDS 연결 → 폰트 및 에셋 설정 → 공용 컴포넌트 구현 순서로 진행 예정
Expo Router를 쓰면 app 폴더가 라우팅 전용이 되니까, 화면 로직은 features 쪽에 두고 app 안의 파일은 해당 화면 컴포넌트를 re-export만 하도록 얇게 유지하면 구조가 덜 섞여요. 그리고 tsconfig paths에 @/features 같은 별칭을 잡아 두면 폴더를 옮길 때 import 수정이 훨씬 줄어들어요.