본문 바로가기
web/react

[React] VAC Pattern을 적용해 관심사 분리하기

by fien 2023. 12. 5.

VAC(View Asset Component) Pattern

View Logic과 렌더링을 분리하여 개발하는 설계 방식

const SpinBox = () => {
  const [value, setValue] = useState(0);

  return (
    <div>
      <button onClick={() => setValue(value - 1)}>-</button>
      <span>{value}</span>
      <button onClick={() => setValue(value + 1)}>+</button>
    </div>
  );
};

VAC

props를 통해서만 제어 되고 스스로 상태를 관리 하지 않는 Stateless component

// VAC
const SpinBoxView = ({ value, onIncrease, onDecrease }) => (
  <div>
    <button onClick={onDecrease}>-</button>
    <span>{value}</span>
    <button onClick={onIncrease}>+</button>
  </div>
);
// View Component
const SpinBox = () => {
  const [value, setValue] = useState(0);

  const props = {
    value,
    onDecrease: () => setValue(value - 1),
    onIncrease: () => setValue(value + 1),
  };

  // JSX를 VAC로 교체
  return <SpinBoxView {...props} />;
};
// VAC 잘못된 예시
const SpinBoxView = ({ value, step, handleClick }) => (
  <div>
    <button onClick={() => **handleClick(value - step)**}>-</button>
    <span>{value}</span>
    <button onClick={() => **handleClick(value + step)**}>+</button>
  </div>
);

UI개발자와 FE개발자가 따로 있을 때 작업이 충돌하는 걸 방지 할 수 있다. UI 개발과 FE 개발을 나눠서 할 수 있기 때문에 분업할 때 유용하다.

<button onClick={() => setValue(value - 1)}>-</button>

=> <button class="**button**" onClick={() => setValue(value - 1)}>-</button>
=> <button onClick={() => **setValue(value - 2)**}>-</button>

VAC pattern 을 적용할 때 유의할 점

props 네이밍은 데이터 친화적인 형태 보다는 렌더링에 직관적인 형태로 사용하는 것이 좋습니다.

isMax, isMin 보다 disabledDescrease, disabledIncrease가 렌더링에서 어떤 역할을 하는지 유추하기 더 쉽습니다.

또 여러 정보를 사용하는 경우 개별로 전달하는 것 보다는 조합된 결과만 전달하는 것이 좋습니다. 로그인 한 상태에서 작성자 본인이면 수정 버튼을 노출하는 조건을 처리한다고 했을 때, isLogin, isOwner을 각각 전달 받아 VAC 내에서 isLogin && isOwner 형태로 사용하는 것 보다는 showEditButton: isLogin && isOwner 형태로 처음부터 조합해서 전달하는 것이 좋습니다.

Presentational 컴포넌트 (Presentational and Container Pattern)

  • 비즈니스 로직과 View의 관심사 분리가 목적
  • Container 컴포넌트에서 비즈니스 로직을 관리하고 Presentational 컴포넌트를 제어
  • Presentational 컴포넌트는 View 로직(UI 기능, 상태 관리)과 렌더링을 담당

VAC

  • View 로직(UI 기능, 상태 관리)과 렌더링(JSX)의 관심사 분리가 목적
  • View 컴포넌트가 Props Object를 관리하여 VAC를 제어
  • VAC는 JSX, Style을 관리하여 렌더링 처리

VAC는 stateless 컴포넌트로 스스로의 상태를 제어하지 않고 항상 부모 컴포넌트에서 Props Object를 통해 관리합니다. 따라서 VAC는 Presentational 컴포넌트보다 더 구체적인 기준을 제시하여 JSX를 처리하는 컴포넌트 관점에서 일관성 있는 설계를 하는데 도움을 줍니다.

장점

  • 관심사가 분리되어 코드 파악이 쉬워짐
  • ui를 재사용하기 좋아짐

단점

  • Props 드릴링이 발생
  • DOM을 직접 핸들링하는 경우에는 적용하기 쉽지 않다

 

VAC Pattern 적용후기

 

몇주간 VAC Pattern을 적용해서 개발해본 결과 관심사가 분리되는 게 가장 큰 장점인 것 같습니다.

이전에는 로직부분과 UI를 컨트롤하는 부분이 뒤섞여 있었는데 이걸 분리하니 코드 파악이 용이하고 심적인 편안함이 있달까..

컴포넌트를 분리했기 때문에 코드량은 늘었지만 실질적인 업무량이 크게 늘어난 것은 아니라 괜찮았습니다

다만 컴포넌트의 복잡도에 따라 Props가 많아지는 것은 부담이 있습니다.

 

처음 적용할 때는 관심사 분리를 제대로 하지 못해서 

Container(비지니스로직) - View Component(UI 처리) - View Asset Component(View) 로 나누어서 관심사를 정확히 분리하려고 했는데 

역시 하다보니 엄격하게 떨어지지 않는 부분이 더러 존재하는 것 같습니다. Props가 커지는 것과 엮어서 VAC는 반드시 stateless 여야만 하는지 하는 생각이 들 때가 있더라구요. 

그리고 필요에 따라서 간단한 경우는 Container - Presentational 컴포넌트로 분리하여 개발을 했습니다. 

 

VAC Pattern을 적용하면서 지금까지 관심사 분리가 제대로 되지 않았구나 체감했고 앞으로도 이 패턴을 적용해 개발을 할 생각입니다.

 

 

참고 자료

https://wit.nts-corp.com/2021/08/11/6461

 

React에서 View의 렌더링 관심사 분리를 위한 VAC 패턴 소개 | WIT블로그

React에서 View의 렌더링 관심사 분리를 위한 VAC 패턴 소개 시작하며 FE개발에서 View는 정보의 시각화 뿐만 아니라 사용자와 상호작용하는 역할을 포함하고 있습니다. 그래서 View를 개발하는 것은

wit.nts-corp.com

https://tv.naver.com/v/23162062

 

React VAC Pattern - View 로직과 JSX의 의존성을 최소화 하자!

NAVER D2 | 발표자: 박우영 (N Tech Service) 발표월: 21.10. React 협업이 어려운 점을 살펴보고 View 로직과 JSX를 격리해서 관리하는 것을 소개합니다. 목차 1. React 협업 - React 환경에서 Front-End 업무는 어떻

tv.naver.com

 

댓글