본문 바로가기
STUDY/CS

뷰 에셋 컴포넌트 (VAC, View Asset Component)

by bottlesun 2022. 12. 27.
728x90

개요

JSX와 Style를 관리하여 UI와 비즈니스 로직을 분리하는데, 목적을 둔 컴포넌트 설계 방법론이다.

Normal Pattern 특징

Business Logic과 UI 처리를 바인딩 하여 개발을 하게 된다.

jsx, view logic, business logic 이 혼합(같이)하여 사용

FE 데이터 작업 과정에서 단순한 props 나 state 를 수정함에 있어서도, JSX 영역에 대한 수정이 필요하다. 이때, UI 처리와 바인딩 부분이 같은 페이지였을 경우, 영역 겹침으로 인한 코드 충돌이 발생한다.

VAC Pattern 특징

view logic과 JSX 와 컴포넌트로 분리에 대한 가이드를 제공하는 디자인 패턴.

  • 반복, 조건부 노출 등 스타일 제어 렌더링에 관련된 처리만 수행
  • props 를 통해서만 제어되며, 스스로의 상태를 관리하지 않는 stateless 컴포넌트
  • 이벤트에 함수를 바인딩 할 때 추가 처리 없이 적용

예제

Normal Pattern

spinBox.jsx 컴포넌트 영역에 모든 구성 요소들이 다 같이 있는 가장 일반적인 구성 요소이다.

// **Normal Pattern Logic**
const SpinBox = () => {
  const [value, setValue] = useState(0);
	
<!--------------------- props Object ----------------------->
	const onDecreas = () => setValue(value - 1); 
	const onIncrease = () => setValue(value + 1); 
<!--------------------- props Object ----------------------->

  return (
<!--------------------- view 영역 ----------------------->
    <div>
      <button onClick={onDecreas}>-</button>
      <span>{value}</span>
      <button onClick={onIncrease}>+</button>
    </div>
<!--------------------- view 영역 ----------------------->

  );
};

VAC PAttern

SpinBoxView.jsx VAC 영역을 만들어, Business Logic 영역과 분리 한다. (VAC 생성)

// **VAC PAttern Logic
//** SpinBoxView.jsx

// 데이터 바인딩부분은 SpinBox 가 담당하기에 styles 영역에 관한 부분만 신경쓴다.

const SpinBoxView = ({ value, onIncrease, onDecrease }) => (
  <div>
    <button style={{bacgkround:red}} onClick={onDecrease}>-</button>
    <span>{value}</span>
    <button onClick={onIncrease}>+</button>
  </div>
);
// **Business Logic**
// SpinBox.jsx

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

// Props Object <- 여기에다 추가
const props = {
    value,
    onDecrease: () => setValue(value - 1),
    onIncrease: () => setValue(value + 1),
  };

  // rendering 부분은 VAC 가 담당하기에 props 부분만 작업 하고 신경쓴다.
  return return <SpinBoxView {...props} />;
};

VAC PAttern <TS 적용>

Props 가 가져야 할 값을 interface로 구현하여 View에 조금 더 직관적인 props 들을 넘길 수 있다.

또한, 내려온 props 만 보고 UI를 설계하고 작업 할 수 있다는 장점까지 생긴다.

Business Logic - BusinessComponent.tsx

import {ChangeEvent, FormEvent} from "react";
import useInput from "../../../hooks/useInput";
import {ViewComponent} from './viewComponent'

export interface VAC<T> {
  onChange: (e: ChangeEvent<HTMLInputElement>) => void,
  onSubmitHandler: (event: FormEvent<HTMLFormElement>) => void
  Email: T,
  Password: T,
  Name: T,
  ConfirmPassword: T
}

export const BusinessComponent = () => {
  const {onChange, inputs} = useInput({Email: '', Password: '', Name: '', ConfirmPassword: ''});
  const {Email, Password, Name, ConfirmPassword} = inputs;

  const onSubmitHandler = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();

  }

  const props = {
    onSubmitHandler,
    onChange,
    Email, Password, Name, ConfirmPassword
  }

  // rendering 부분은 VAC 가 담당하기에 props 부분만 작업 하고 신경쓴다.

  return <ViewComponent {...props} />
};

 

VAC PAttern Logic - ViewComponent.tsx

// 데이터 바인딩부분은 SpinBox 가 담당하기에 styles 영역에 관한 부분만 신경쓴다.
import React from "react";
import {VAC} from "./businessComponent";

export const ViewComponent = ({onSubmitHandler, onChange, Email, Password, Name, ConfirmPassword}: VAC<string>) => (

  <div className={'wrap'}>
    <form onSubmit={onSubmitHandler} className={'login-form'}>

      <label htmlFor="{'input-email'}">Email</label>
      <input type="email" name={'Email'} id={'input-email'}
			 defaultValue={Email} onChange={onChange}/>

      <label htmlFor="{'input-name'}">Name</label>
      <input type="text" name={'Name'} id={'input-name'}
		     defaultValue={Name} onChange={onChange}/>

      <label htmlFor="{'input-password'}">Password</label>
      <input type="password" name={'Password'} id={'input-password'}
             defaultValue={Password} onChange={onChange}/>

      <label htmlFor="{'input-ConfirmPassword'}">Confirm Password</label>
      <input type="password" name={'ConfirmPassword'} id={'input-ConfirmPassword'}
					defaultValue={ConfirmPassword} onChange={onChange}/>

      <button type={'submit'}>
        Login
      </button>
    </form>
  </div>
);

장점

TypeScript의 직관적 사용

Storybook을 통한 독립적인 UI 테스트에 유리

비지니스 로직 변경에 유리

단점

Props가 많이 질 수 있음


[참고자료]

react-vac

[리액트] VAC 패턴 적용 후기 및 장단점

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

728x90

댓글