MVVM 패턴과 React

일어나 개발해야지·2025년 1월 14일

React 아키텍처

목록 보기
1/2
post-thumbnail

Architecture Design Pattern의 필요성

  • 코드의 구조를 체계화 하기 위해 등장한 개념
  • 규칙이 없는 상태에서 코드가 늘어나면 확장성에 문제가 생김
  • 코드의 혼재로 인한 버그를 줄이기 위해서는 체계적인 구조가 필요하겠다는 문제의식
  • "코드를 어떻게 정리할까 ?" 라는 고민에서 디자인 패턴이 등장

아키텍쳐 디자인 패턴의 종류

MVCMVPMVVM
Model - View - ControllerModel - View - PresenterModel - View- ViewModel
Controller가 View와 Model 사이를 중재Presenter가 View와 Model 간의 모든 논리를 관리ViewModel이 비지니스 로직을 담당

MVVM 패턴과 React

React 에 가장 적합한 디자인 패턴이 MVVM이라고들 하는데, 그 이유가 뭘까

* React
	- Component 기반으로 UI를 설계
    - State와 Props를 사용한 단방향 데이터의 흐름
    
* MVC 
	- Controller가 View와 Model을 직접연결하고 있기 때문에, 
	  단방향 데이터의 흐름을 구현하기 어려움
* MVP 
	- Presenter를 통해서 단방향 데이터의 흐름은 구현이 가능하나,
	  View와 Presenter의 결합도가 높음
* MVVM 
	- ViewModel이 상태를 관리하고, View에서 이를 보여주는 방식이라 
	  단방향 데이터 흐름과 역할을 구분을 명확하게 구분할 수 있음
		

MVVM 패턴은 React의 상태 관리 방식과 잘 맞아떨어지며,
View와 Model 간의 느슨한 결합(Loosely Coupled Structure) 을 가능하게 한다.
따라서 React와 MVVM은 가장 자연스럽고 이상적인 조합이라고 한다.

MVVM 구성요소의 역할과 구현

MVVM 폴더 구조

src/
│
├── model 
│   ├── api 
│   ├── recoil
│   └── type
│
├── view 
│   ├── component 
│   ├── navigaton 
│   └── screens
│       
└── view-model 
		

Model

  • 데이터의 상태를 나타내는 객체
  • 데이터비지니스 로직을 담당하는 계층
  • api / recoil / type 폴더
//user.ts

export const userInfoState = atom<MemberInfoType>({
  key: 'userInfoState',
  default: defaultUserInfo,
})

View

  • 사용자에게 보여지는 UI를 담당
  • 사용자의 Action을 View Model에 전달
  • component / view / navigation 폴더
const EditUserInfo_View = () => {
  const {memberInfo, formatAddress, addCertifyIcon} = useEditUserInfo_ViewModel()
  const navigation = useNavigation<NativeStackNavigationProp<any>>()
  const certifyIconData = addCertifyIcon()

  return (
    <SafeAreaView className={'bg-white'}>
      <HeaderGoBackImg goBack={navigation.goBack} title={'내 정보_MVVM'} />

      <View className={'flex items-center mx-5 h-full '}>
        <InfoRow label={'아이디'} value={memberInfo.id} onPress={() => {}} />

        <InfoRow label={'활동명'} value={memberInfo.name} />

        <View className={'flex justify-center items-center w-full mt-7 px-10'}>
          <WidthFullButton
            title={isToggled ? 'On' : 'Off'}
            onPress={() => {
              handleButtonTitle()
            }}
          />
        </View>
      </View>
    </SafeAreaView>
  )
}

export default EditUserInfo_View

View - Model

  • UI의 상태를 관리
  • View와 Model 사이의 중간 다리
  • View가 필요로하는 데이터를 제공하고, 사용자 입력을 처리해서 Model에 반영
  • view-model 폴더 (useState / useEffect / UI 관련 함수)
import {useRecoilValue} from 'recoil'
import {userInfoState} from '../model/recoil/member.ts'

export const useEditUserInfo_ViewModel = () => {
  const memberInfo = useRecoilValue(userInfoState)

  const formatAddress = (contents: any) => {
    if (contents === null) {
      return ''
    }

    return contents
  }

  const addCertifyIcon = () => {
    if (!memberInfo.email) return null
    return {
      iconSource: require('../../../assets/profile/bule-certify-mark.png'),
      emailText: memberInfo.email,
    }
  }

  return {
    memberInfo,
    formatAddress,
    addCertifyIcon,
  }
}

MVVM 패턴은 어떻게 코드 정리를 돕는가 ?

  • 책임과 역할의 분배
  • Test code 작성 시 ViewModel을 중심으로 검증 가능
  • singleton으로 제작된 ViewModel은 여러 View에 대응이 가능하기에 중복되는 코드를 방지 할수있다.

MVVM 사용의 단점

  • 파일의 수 증가
  • JSX 태그를 직접 return 할 수 없음

MVVM 사용의 장점

  • 가독성 및 유지보수성 향상
  • 하나의 ViewModel이 여러 View에 대응 할수있기때문에 확장성 증가
  • ViewModel의 데이터 바인딩으로 UI 업데이트 간소화
- useState와 useEffect를 상태를 업데이트 하는 방식은 수동
- ViewModel에 포함된 상태값(useState)이 바뀌면 그것과 연결된 UI도 다시 렌더링 되는 자동 방식 지원
 

Next

Custom Hook으로 동일한 상태값을 제공할 수 있는가?

0개의 댓글