React, Vue만 하다 처음으로 앱 개발을 맞닥뜨리게 된 시행착오 기록

구조에서 막혔다
React, Vite, TypeScript에 익숙해서
프로젝트 구조를 짤 때도 당연히 src/, components/, pages/를 생각했다.
근데 Expo Router로 React Native 앱을 시작하니까 이렇게 생겼다:
app/
├── index.tsx
├── trip/
│ └── index.tsx
components/
constants/
❓ 뭐지? src도 없고, app/이 루트 폴더네?
📂 app/ = pages/ 디렉토리 (파일 기반 라우팅)
기존 React Web처럼 react-router 쓰는 게 아니라,
Next.js처럼 파일 구조 = 라우팅 구조였다.
app/
├── index.tsx # / (홈)
├── trip/index.tsx # /trip
├── trip/[id].tsx # /trip/:id
💡 app/ = 웹의 /pages라고 보면 됨!
app/은 라우트 역할만 하도록 두고 실제 UI, 로직, 훅, 상태는 전부 분리했다:
components/ # UI 컴포넌트
stores/ # 상태관리 (Zustand)
constants/ # 상수/설정
hooks/ # 커스텀 훅
utils/ # 유틸 함수
구조만 보면 React Web과 크게 다르지 않다.
⚡ 문제: 한 페이지에서 여러 화면이 바뀌는 경우는???
React Web에선 라우팅을 쪼개서 해결했는데,
앱에선 주소창이 없으니까 자연스럽게 한 페이지 안에서 처리해야 한다.
const [images, setImages] = useState([]);
const [address, setAddress] = useState('');
const [tags, setTags] = useState([]);
const [showSearchModal, setShowSearchModal] = useState(false);
return (
<>
<PhotoUploader />
<AddressDisplay onEdit={() => setShowSearchModal(true)} />
<TagEditor />
{showSearchModal && <AddressSearchModal />}
</>
);
페이지 전환 X, 상태값으로 흐름을 전환
느낌은 React에서 조건부 렌더링하듯 작성
app/
└── place/
└── upload.tsx # 한 페이지 안에서 상태 전환만
components/
└── place/
├── PhotoUploader.tsx
├── AddressSearchModal.tsx
└── TagEditor.tsx
stores/
└── placeUploadStore.ts # Zustand 상태 저장소
hooks/
└── useUploadValidation.ts # 예: 사진, 주소 없으면 비활성화
React Native = 새로운 생태계지만 React 경험이 있다면 90%는 같다.
단지 라우팅 구조, 상태 기반 전환, 모달/시트 활용 방식이 다를 뿐!
Next를 해보고 시작할 걸 살짝 후회되는 시간이었다.
app/ = 라우트 단위 (파일 기반 Next.js처럼)
화면에 따라 UI를 나누고 싶다면 components/에 분리
다단계 입력이라면 페이지 전환 대신 상태 분기
상태 공유는 Zustand, Jotai 등 웹이랑 똑같이 사용하면 됨.
(zustand 쓸 예정)