본문으로 바로가기

회사에서는 hook기반 MVC에서 MVVM로 이전이 진행되고 있다.

지그재그에서도 프론트엔드에서 디자인 패턴으로 MVVM을 채용했다고 한다. (2021년 9월 현재 기준으로는 모르겠다.)

 

기존 MVC 패턴에 대해서

 

가장 직관적인 패턴이다.

 

1. redux에 데이터를 쌓아놓고

2. 필요할 때 useSelector로 container 컴포넌트에서 store값을 불러오고

3. presenter 컴포넌트에서 해당 값을 사용한다.

 

 

도대체 왜 이게 문제가 될까?

container 컴포넌트가 함수를 선언과 조합이라는 두 가지 역할을 다 하고 있어서 필연적으로 props가 많아질수록 번잡해진다.

MVC로 담기에 컴포넌트의 복잡도가 매우 높은 경우다. 회사에서 사용하는 컴포넌트에서 자식 컴포넌트로 넘겨주는 props만해도 수십개가 되는 기염을 토했고, 이벤트 핸들러도 쌓이고 쌓여 도저히 깔끔하게 유지가 안되는 수준이었다.

 

잠깐! container/presenter는 hook이 등장하면서 구식이 된 패턴이 아닌가?

맞다고는 하지만, 커스텀 훅으로 빼기 애매한 로직이 쌓이고 쌓여 거대해질 수 있다. 구식이라고 놔버리지 말고, 적절한 패턴을 필요에 따라 적절하게 사용하면 되는 일이다.

 

여튼, MVC 패턴의 한계에 봉착한 컴포넌트를 대략 묘사해보자면 다음과 같은 꼴이었다. 후우...

function MyComponent() {
    query = useMemo(() => createQuery, [])
    service = useMemo(() => createService, [])
    
    // customhook1()
    // customhook2()
    // ...
    
    // helper1
    // helper2
    // ...
    
    // eventhandler 1
    // eventhandler 2
    // ...
    // eventhandler 36
    
    return (
      <>
        <Child
          onClick={}
          onMouseOver={}
          prop1={}
          prop2={}
          ...
          prop36={}
        >
      </>
    )
}

 

 

MVVM 패턴을 사용하면 괜찮아질까?

우선 MVVM 패턴은 모바일 개발에서 흔히 사용되는 디자인 패턴인데, 웹 프론트엔드도 복잡해지면서 이 패턴을 차용하는 프로젝트가 생겼다. 

 

1. 우선 데이터는 store에 쌓인다. M(model)

2. useSelector로 불러오는 데이터들을 가공하는 VM(View Model)이 중간에 존재한다. VM의 예시로, 단순힌 유틸 함수 모음집일 수도 있고, 커스텀 훅이 VM 역할을 한다. (커스텀 훅은 반드시 React가 제공하는 훅이 필요할 때만 사용해야 하며, memoization을 적극적으로 활용하도록 하자. 커스텀 훅이 여기 돌고 저기 돌아버리면 나중에 미춰버린다....)

3. Container에서는 VM에서 필요한 로직을 불러와 사용한다.

4. Presenter는 container에서 들어와 사용한다.

 

 

잠깐, MVVM을 따른다고 하더라도 어차피 container에 잔뜩 들어간 props를 줄일 수는 없는 것 아닌가?

맞다. 다만 container 내부에서 함수를 선언하고 조합하는 코드가 VM으로 빠져서 좀 더 깔끔하게 관리할 수 있으며, 추후 메모이제이션 등을 적용할 때 편리하다는 장점이 있다.

 

생각해자.

1) 특정 함수가 컴포넌트 내부에 선언되어 있고, 그 함수가 다른 함수의 내부에서 또 사용되면 함수 간의 상관관계 때문에 memoization을 하기가 너무 힘들어진다.

2) 정의된 함수들이 useEffect 내부에서 동작하는 동시에 의존성을 가진 state들이 reference type이라면? 그리고 그 state들이 한 두개가 아니라면?

 

생각만해도 골치아파진다.. 이런 지점을 조금이나마 해소하기 위해서 MVVM 패턴을 사용하는 것이다.

 

그래서 구체적으로 폴더 구조는 어떻게 해야 좋나?

 

이렇게 말로만 하니 이해가 잘 안 갈 수 있다. 특정 feature를 구현하는데 필요한 폴더 단위를 가져봐오면 다음과 같다.

이제는 대충 감이 온다.

📁 clipboardAction
ㄴ 🪝 hooks
  ㄴ 🪝 useClipboardAction.js (VM)
  ㄴ 🪝 useClipboardToolbar.js (VM)
ㄴ clipboardAction.util.js (VM)
ㄴ clipboardActionSlice (redux store)
ㄴ ClipboardToolBar.js (simple component) // 단순하니 굳이 container/presenter 분리 필요 X
ㄴ ClipboardCard.container.js (container component)
ㄴ ClipboardCard.presenter.js (presenter component)

 

 

 

darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체