내가 MVVM을 활용해 확장 가능한 React Native 앱을 구조화하는 방법
Source: Dev.to
React Native 앱이 커지면 피할 수 없는 문제가 하나 생깁니다: 코드가 엉망이 되기 시작한다는 점입니다.
단순한 컴포넌트 구조였던 것이 서서히 다음과 같이 변합니다:
- 서로 강하게 결합된 로직
- 유지보수가 어려운 화면
- 예측할 수 없는 상태 관리
저는 실제 서비스 앱을 개발하면서 이 문제를 겪었고, 그때부터 **MVVM (Model–View–ViewModel)**이라는 보다 구조화된 접근 방식을 채택하기 시작했습니다.
왜 React Native 앱은 확장하기 어려워지는가
많은 프로젝트에서 로직이 컴포넌트 내부에 들어가게 됩니다:
- API 호출
- 비즈니스 로직
- 상태 변환
이로 인해 다음과 같은 문제가 발생합니다:
- 가독성 저하
- 테스트 어려움
- 화면마다 중복된 로직
앱이 커질수록 상황은 더욱 악화됩니다.
MVVM이 해결해 주는 것
MVVM은 책임을 다음과 같이 분리합니다:
- Model → 데이터 레이어 (API, 저장소, 타입)
- View → UI 컴포넌트
- ViewModel → 비즈니스 로직 + 상태 관리
이러한 분리는 UI를 깔끔하게 유지하고 로직을 재사용 가능하게 만들어 줍니다.
내 폴더 구조
제가 보통 기능을 구성하는 방식은 다음과 같습니다:
// /features/user
UserView.tsx // View component
useUserViewModel.ts // ViewModel hook
userModel.ts // Model definitions
userService.ts // Data fetching / storage
- View는 렌더링을 담당
- ViewModel은 로직을 관리
- Model/Service는 데이터를 처리
예시: View vs ViewModel
View (UI 전용)
import React, { useEffect } from 'react';
import { Text } from 'react-native';
import { useUserViewModel } from './useUserViewModel';
import Loader from '../components/Loader';
const UserView = () => {
const { user, loading, fetchUser } = useUserViewModel();
useEffect(() => {
fetchUser();
}, []);
if (loading) return ;
return {user?.name};
};
export default UserView;
ViewModel (로직)
import { useState } from 'react';
import { getUser } from '../services/userService';
export const useUserViewModel = () => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const fetchUser = async () => {
setLoading(true);
const data = await getUser();
setUser(data);
setLoading(false);
};
return { user, loading, fetchUser };
};
프로덕션에서 잘 작동하는 이유
- 로직을 별도로 테스트하기 쉬움
- 비즈니스 로직 재사용 가능
- UI 컴포넌트가 깔끔함
- 팀 협업이 개선됨
가장 중요한 점은 동일한 로직을 여러 곳에서 다시 작성하지 않게 된다는 것입니다.
Redux와의 연계
Redux를 사용한다면:
- 전역 상태는 Redux에 보관
- 화면 별 로직은 ViewModel에 보관
이렇게 하면 불필요한 복잡성으로 Redux를 과부하 시키는 일을 피할 수 있습니다.
피해야 할 흔한 실수
- 모든 것을 Redux에 넣기
- UI와 비즈니스 로직을 섞어버리기
- 작은 기능을 과도하게 설계하기
MVVM은 앱을 단순화하기 위한 것이지 복잡하게 만들기 위한 것이 아닙니다.
마무리 생각
React Native는 아키텍처를 강제하지 않으며, 이는 장점이자 단점이 될 수 있습니다.
초기에 구조를 정의하지 않으면 확장할 때 고통스러워집니다.
저에게 MVVM은 다음과 같은 면에서 간단하고 효과적인 방법이었습니다:
- 코드 정리
- 유지보수성 향상
- 보다 예측 가능한 앱 구축
유일한 접근법은 아니지만, 실제 프로젝트에서 잘 작동하는 방법 중 하나입니다.