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

시작하며

FE개발에서 View는 정보의 시각화 뿐만 아니라 사용자와 상호작용하는 역할을 포함하고 있습니다.
그래서 View를 개발하는 것은 크게 아래와 같이 세 가지 영역으로 나눌 수 있습니다.

  1. 사용자의 상호작용을 처리하는 UI 기능 개발(JS 등)
  2. 데이터나 상호작용 결과를 시각화하는 렌더링 처리(마크업, CSS 등)
  3. 비즈니스 로직, UI 기능, 렌더링 처리의 통합(React, Redux 등)

네이버를 비롯한 많은 개발조직들은 디자인 영역과의 원할한 협업을 위해 2번에 해당하는 UI개발(마크업 개발) 영역과 1, 3번에 해당하는 FE개발 영역으로 역할이 나뉘어 있습니다.
하지만 React에서는 컴포넌트를 개발할 때 JSX로 렌더링을 처리하는 방식을 주로 사용하기 때문에 JS와 마크업이 혼합된 형태로 개발이 됩니다.
따라서 FE개발자와 UI개발자가 JSX를 함께 관리하게 되면서 종종 코드 충돌이 생기고, FE개발자가 개발을 완료한 컴포넌트에 대해서 UI개발자가 JSX를 수정하는 것이 쉽지 않은 문제가 있습니다.

물론 React 환경에서도 효율적으로 코드를 설계하고 관리하기 위해서 비즈니스 로직과 View의 관심사를 분리하는 방법에 대한 고민이 많이 있었는데, Custom Hook을 활용하거나 Presentational과 Container 컴포넌트 패턴이나 BLoC 패턴 같은 디자인 패턴들이 존재하고 있습니다.
그러나 대부분은 비즈니스 로직의 관점에서 관심사를 분리하고 있어 View를 설계하는데 도움은 되지만 역할 분담에 따른 협업 과정에서 발생하는 문제를 해결하는데 있어서는 개발자의 경험에 따른 차이가 발생하게 됩니다.

이 글에서는 React 환경에서 UI개발자와 FE개발자의 협업 문제를 해결하기 위해 View 컴포넌트에서 JSX 영역을 분리하는 VAC 패턴에 대해 소개하고, Presentational과 Container 컴포넌트 패턴과 어떻게 다른지 설명합니다.

VAC Pattern

VAC는 View Asset Component의 약자로 렌더링에 필요한 JSX와 스타일을 관리하는 컴포넌트를 의미합니다.
VAC 패턴은 View 컴포넌트에서 JSX 영역을 Props Object로 추상화하고, JSX를 VAC로 분리해서 개발하는 설계 방법입니다.
이런 설계는 비즈니스 로직 뿐만 아니라 UI 기능 같은 View 로직에서도 렌더링 관심사를 분리하는데 목적이 있습니다.

VAC는 다음과 같은 특징을 가지고 있습니다.

  • 반복이나 조건부 노출, 스타일 제어와 같은 렌더링과 관련된 처리만을 수행합니다.
  • 오직 props를 통해서만 제어되며 스스로의 상태를 관리하거나 변경하지 않는 stateless 컴포넌트입니다.
  • 이벤트에 함수를 바인딩할 때 어떠한 추가 처리도 하지 않습니다.

VAC는 state를 가질 수 없지만 state를 가진 컴포넌트를 자식으로 가지는 것은 가능합니다. 이 경우 VAC는 부모 컴포넌트와 자식 컴포넌트 중간에서 개입하지 않고 단순히 props를 전달하는 역할만 합니다.

구현 예제

간단한 SpinBox UI 컴포넌트를 통해 VAC를 만드는 방법을 알아봅시다.

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>
  );
};

예제는 +, – 버튼을 클릭하면 값이 1씩 증가하거나 감소하는 UI 기능을 포함하고 있습니다.

Props Object 정의

View 컴포넌트에서 JSX를 추상화한 Props Object를 생성하고 JSX에서 사용할 상태정보나 이벤트 핸들러를 정의합니다.

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

  // JSX를 추상화한 Props Object
  const props = {
    value,
    onDecrease: () => setValue(value - 1),
    onIncrease: () => setValue(value + 1),
  };

  // JSX의 유무는 중요하지 않음
  return <div></div>;
};

JSX를 VAC로 분리

JSX영역을 분리하여 VAC로 만듭니다. 이때 View 컴포넌트에 생성한 Props Object 속성을 참고하여 VAC의 Props를 정의합니다.
반대로 이미 만들어진 VAC를 View 컴포넌트에 적용할 때는 VAC의 Props를 참고하여 View 컴포넌트의 Props Object 속성을 정의합니다.

// 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 Debugger 활용

만약 VAC가 개발되기 전에 Props Object를 테스트해보고 싶다면 VAC Debugger를 활용할 수 있습니다.

// VAC Debugger
import VAC from "react-vac";

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

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

  // VAC Debugger로 Props Object 테스트
  return <VAC name="SpinBox" data={props} />;
};

VAC Debugger를 사용하여 Todo List를 테스트하는 예제

Props Object를 사용하는 이유

Props Object와 VAC를 사용하지 않고 직접 변수를 선언해 JSX 영역에서 UI 기능의 의존성을 줄이는 것도 가능합니다.
하지만 이렇게 개발 하는 경우는 UI 기능이 복잡해서 변수나 hook이 많을 때 어떤 것을 JSX에서 사용하는지 한눈에 파악하기가 어렵고 디버깅 하기가 번거롭습니다. 또 View 컴포넌트 내에서 JSX를 관리하고 있어서 간단한 상태처리의 경우 무의식중에 JSX에서 바로 적용할 가능성이 있습니다.

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

  // JSX에서 사용할 값을 미리 선언하여 JSX에 적용
  const onDecrease = () => setValue(value - 1);
  const onIncrease = () => setValue(value + 1);

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

잘못된 VAC 적용 예시

다음과 같이 View 컴포넌트의 기능이나 상태 제어에 VAC가 관여해서는 안됩니다.

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

  const props = {
    value,
    step: 1,
    handleClick: (n) => setValue(n),
  };

  // VAC에서 value를 제어하는 행위에 관여
  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>
);

올바른 VAC는 핸들러를 이벤트에 바인딩만 할 뿐, 무엇을 하는지에 대해서 관여하지 않습니다.

// VAC
const SpinBoxView = ({ value, onIncrease, onDecrease }) => (
  <div>
    <button onClick={onDecrease}>-</button>
    <span>{value}</span>
    <button onClick={onIncrease}>+</button>
  </div>
);

역할에 따른 작업 공간의 분리

예를 들어 SpinBox의 최소 값을 0이하로 설정할 수 없는 조건과 증가 감소 버튼을 둥글게 처리하는 디자인 수정이 발생했다고 가정해봅시다.

일반적인 상황

FE개발자는 자신의 로컬에서 SpinBox 컴포넌트의 감소 버튼 핸들러를 onClick={() => setValue(Math.max(value - 1, 0))} 형태로 기능을 수정합니다.

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

  return (
    <div>
      <button onClick={() => setValue(Math.max(value - 1, 0))}>-</button>
      <span>{value}</span>
      <button onClick={() => setValue(value + 1)}>+</button>
    </div>
  );
};

UI 개발자는 자신의 로컬에서 SpinBox 컴포넌트의 버튼에 style을 적용할 className="round"를 추가합니다.

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

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

이제 서로의 결과물을 저장소에 push 하면 다음 부분에서 충돌이 발생합니다.

// FE 수정
<button onClick={() => setValue(Math.max(value - 1, 0))}>-</button>

// UI 수정
<button className="round" onClick={() => setValue(value - 1)}>-</button>

VAC Pattern 적용

FE개발자는 로컬에서 View 컴포넌트의 Props Object에 있는 onDecrease를 수정합니다.

// VAC Debugger
import VAC from "react-vac";

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

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

  // VAC Debugger로 Props Object 테스트
  return <VAC name="SpinBox" data={props} />;
};

UI개발자는 VAC에서 style을 적용합니다.

// VAC
const SpinBoxView = ({ value, onIncrease, onDecrease }) => (
  <div>
    <button className="round" onClick={onDecrease}>
      -
    </button>
    <span>{value}</span>
    <button className="round" onClick={onIncrease}>
      +
    </button>
  </div>
);

FE개발자는 View 컴포넌트에서 기능을 수정하였고, UI개발자는 VAC에서 JSX를 수정하여 충돌이 발생하지 않습니다.

렌더링에 직관적인 상태 관리

SpinBox 기능이 0 ~ 10 범위만 사용하도록 증가 감소 버튼의 disabled 상태를 처리한다고 가정해봅시다.

일반적인 상황

JSX에 직접 disabled 조건을 처리합니다.

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

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

VAC Pattern 적용

Props Object에서 VAC 속성을 정의하여 사용하기 때문에 렌더링에 더 직관적인 형태로 상태를 관리할 수 있습니다.

View 컴포넌트에서는 JSX에 어떻게 상태가 적용되는지 신경 쓸 필요가 없으며, VAC(JSX) 관점에서는 어떤 조건에서 버튼이 활성/비활성 되는지를 파악할 필요가 없습니다.

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

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

  // JSX를 VAC로 교체
  return <SpinBoxView {...props} />;
};
// VAC
const SpinBoxView = ({ value, disabledDecrease, disabledIncrease, onIncrease, onDecrease }) => (
  <div>
    <button disabled={disabledDecrease} onClick={onDecrease}>
      -
    </button>
    <span>{value}</span>
    <button disabled={disabledIncrease} onClick={onIncrease}>
      +
    </button>
  </div>
);

VAC의 props 네이밍은 데이터 친화적인 형태 보다는 렌더링에 직관적인 형태로 사용하는 것이 좋습니다. isMax, isMin 보다는 disabledDescrease, disabledIncrease가 렌더링에서 어떤 역할을 하는지 유추하기 더 쉽습니다.

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

Presentational 컴포넌트와 VAC

VAC 패턴은 Container 컴포넌트에 로직을 위임하는 설계 방식을 따르기 때문에 Presentational과 Container 컴포넌트 패턴의 한 종류라고 볼 수 있습니다. 때문에 VAC가 Presentational 컴포넌트와 동일한 역할을 하는 것 처럼 혼동되는 경우가 있으나, 두 컴포넌트의 근본적인 차이는 컴포넌트가 View 로직(UI 기능, 상태 관리)을 가질수 있는지 여부입니다.

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

Presentational 컴포넌트

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

VAC

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

끝으로

지금까지 소개한 VAC 패턴은 JSX 영역을 View 컴포넌트에서 독립적으로 관리하기 위한 목적을 가지고 만들어진 설계 방법입니다. 이런 이유로, 비즈니스 로직과 View의 관심사를 분리하는 여러 기법이나 패턴을 적용했음에도 여전히 JSX 관리로 인해 UI개발자와 FE개발자가 협업에 어려움이 있다면 VAC 패턴을 활용해보는 것은 어떨까합니다.

참고자료


14개의 댓글

리린이 · 2022년 6월 1일 9:28 오전

너무 좋은 문서 감사합니닷 잘 봤습니닷

고래 · 2022년 6월 9일 1:17 오후

안녕하세요. FE를 공부하고 있는 대학생입니다.
먼저 좋은 글 작성해주셔서 감사합니다.

현재 진행할 프로젝트에 VAC 패턴을 적용해보려고 하는데, 궁굼한 사항이 있어서 댓글을 남기게되었습니다.
제가 이해한 바로는 ‘View component에서 logic을 VAC의 props로 전달해준다’고 이해했습니다.
그렇다면, 하나의 VAC마다 View component를 두는건지 궁굼합니다.

기존에 atomic 패턴으로 개발을 하였는데, 여러 atom이 모여서 큰 component를 이루는 것처럼,
VAC 또한, 하나의 View component에 여러 VAC를 두고, logic을 전달해도 문제가 없는지 궁굼합니다.

긴 글 읽어주셔서 감사합니다.

    박우영 · 2022년 6월 23일 4:57 오후

    안녕하세요. 답변이 많이 늦었네요.
    질문하신 내용은 View 컴포넌트와 VAC가 항상 쌍으로 구성되는지 질문 하신 것으로 이해했습니다.

    VAC의 목적은 JSX에서 로직을 분리하여 렌더링에 집중하기 위함입니다.
    따라서 VAC가 담당하는 렌더링 영역에서 로직을 어떻게 배제하고 순수하게 렌더링에만 집중할 수 있느냐의 관점에서 접근한다면 VAC 외부 상황이 어떤지는 중요하지 않습니다.
    그리고 VAC 외부 상황이라는 것은 단순히 부모 컴포넌트만을 의미하는 것은 아니고 자식 컴포넌트도 포함됩니다.
    로직이 있는 컴포넌트를 자식으로 가지더라도 VAC가 그 로직에 관여하지 않는다면 문제가 없겠죠.

    개발에 정답이 있는 것은 아니기 때문에..
    이렇게 하는게 옳은 방법이냐 보다는, VAC 패턴의 목적이 무엇이고, 내 문제를 VAC가 어떻게 해결해줄 수 있는가를 생각하는게 중요합니다.

    도움이 되었는지 모르겠네요.
    더 궁금한 점 있으면 추가로 질문 부탁드릴게요~

    고맙습니다.

hyeoki · 2022년 6월 13일 5:39 오후

베리굿굿굿

devman · 2022년 8월 17일 1:38 오후

너무 재밋게 읽었습니다
디자인패턴이라는건 정말 잘만쓰면 엄청난 시너지를내는거같네요

thiporia · 2022년 8월 26일 11:55 오전

오 흥미롭게 읽었습니다. 감사합니다. 🙂

green5940 · 2022년 12월 14일 1:07 오후

오 좋은글 감사합니다. 하나 궁금한게 있는데요.view 단의 상태는 오직 props만으로만 제어하는게 mvp 패턴에서 p랑 동일한거 같은데요. 혹시 제가 느낀게 맞는걸까요?

    박우영 · 2022년 12월 15일 11:50 오전

    안녕하세요.

    질문하신 내용은 View에서 props로만 제어하기 때문에 View가 Presenter 역할인지 질문하신 것으로 이해했습니다.
    ‘props로만 제어한다’는 말은 VAC 패턴 여부와는 무관하게 VAC가 stateless 컴포넌트라는 의미로 보시면 됩니다.

    다만 질문 한 것 처럼 설계 방법에 따라 VAC 패턴에서 View의 역할은 Presenter 역할을 하기도 합니다.
    그러나 설계하는 개발자나 시스템에 따라서 View의 경우는 UI기능을 어디까지 포함하는가에 대한 관점의 차이가 발생합니다.
    Presenter 역시 이런 부분이 있을 수 밖에 없는데요.
    위에서 언급한 Spinbox를 예로 들면, MVP에서도 사용자 인터렉션을 통해 1을 더하는 행위나 0보다 큰 경우에 대한 조건 처리를 항상 Presenter에서 처리해서 View에 전달한다는 보장을 할 수 없습니다.
    (물론 VAC도 100% 보장할 수 없는건 마찬가지이나, 적어도 VAC를 지향한다면 그렇게 해야 된다 라는 가이드는 제시하는 것이죠.)

    VAC 패턴에서 포커스를 맞추는 부분은 View에서 UI로직을 제거하는 것이기 때문에, 사실 VAC를 제어하는 View가 Presenter나 ViewModel이 될 수도 있고, Controller 역할을 하는 것도 상관은 없습니다.
    결국 MV* 패턴이나, Hooks 패턴, Controll Props 패턴 등 어떤 설계를 적용하더라도 렌더링을 처리할 때 JSX를 다루는 관점에서는 View 로직을 제거하자는 것이 VAC의 목적이라고 이해하시면 됩니다.
    왜냐하면 JSX를 주로 다루게 되는 마크업, CSS 개발에서 이러한 기능성 로직에 대한 의존성 있으면 FE 개발과 충돌하는 부분이 많아지고 협업이 어려워지기 때문입니다.

    질문에 답변이 되었는지 모르겠네요.
    혹시 더 궁금한 점 있으면 말씀해주세요.

    고맙습니다.

      박우영 · 2022년 12월 15일 11:57 오전

      VAC 패턴에서 포커스를 맞추는 부분은 View에서 UI로직을 제거하는 것이기 때문에, <-
      VAC 패턴에서 포커스르 맞추는 부분은 JSX에서 UI로직을 제거하는 것이기 때문에 로 정정합니다.

chogyejin · 2023년 1월 19일 3:52 오후

안녕하세요! VAC 패턴에 관한 글 중 가장 처음 접했지만 이해하기 쉽게 예시와 함께 잘 작성된 양질의 글이라 너무 읽기 편했습니다.

읽다가 궁금한 점이 생겼는데, VAC 패턴의 장점으로 비즈니스로직을 개발하는 FE개발자와 style 등을 개발할 UI개발자의 충돌 가능성이 줄어든다고 얘기해주셨습니다.
위의 예시에선 기존 존재하는 이벤트 핸들러에 대해 수정을 시도했기 때문에 View 컴포넌트와 asset 컴포넌트의 각각 작업이 가능했지만, 만약 새로운 이벤트를 바인딩하는 상황이라면 이럴 때는 작업공간의 분리 측면에서는 맞지만 충돌이 날 것이라고 일반적인 작성 방식과 동일하게 충돌이 날 것이라고 예상되는데, 오히려 파일이 많아지고 복잡도가 증가한다는 측면에선 어떻게 생각하시는지 궁금합니다!

미리 답변 감사합니다!

    박우영 · 2023년 1월 25일 12:21 오후

    안녕하세요.

    말씀하신 상황과 같이 100% 완전하게 격리한 상태로 진행할 수는 없습니다.
    보통 컴포넌트 초기 설정에서 FE쪽에서 구조를 잡고 시작하는 경우도 있을 수 있습니다.
    실제로 이렇게 하는 경우가 많더라구요..
    그리고 모든 컴포넌트를 VAC로 분리해야 할 필요는 없습니다.
    대체로 기본 UI 컴포넌트의 경우 단순하기도 하고 한번 만들면 수정이 거의 없기 때문에
    기본 컴포넌트 같은 것들은 VAC로 분리하지 않고,
    그보다는 수정이 좀 더 빈번할 수 있는 컴포넌트를 조합해서 사용하는 영역에서 VAC를 적용할 수도 있습니다.
    그래서 협업하는 분들이 이런 상황이 발생했을 때 어떻게 롤을 가져갈지에대 해서 사전에 커뮤니케이션이 필요합니다.

    예를 들면 FE 개발자가 필요한 이벤트를 VAC의 props에 추가하는 부분은 직접하고,
    추가된 props를 JSX에 적용하는건 UI개발자가 진행할 수도 있죠.
    아니면 FE개발에서 필요한 props를 작업하기 전에 UI개발자에게 추가해달라고 요청할 수도 있구요.
    물론 작업방식은 각자의 상황에 맞게 협의를 해야 할 거라고 생각됩니다.

    VAC 패턴 자체가 작업 영역을 분리하는 형태로 어느정도의 이해를 가지고 출발하는 것이라서
    VAC 방식이 아닌 상황에서 논의하는 것 보다는 명확하게 롤을 정하는데 도움이 될 것이라고 생각합니다.
    VAC 구조에서는 일반적인 상황에서는 이벤트를 바인딩할 때 동작에 대한 추가 작업이 필요하지 않으니까요.

    혹시 추가로 궁금한 점 있으면 말씀해주세요~
    고맙습니다.

joo · 2023년 6월 13일 2:54 오후

안녕하세요.
글 잘 읽었습니다.
한 가지 궁금한 점이, VAC구조를 사용할 경우 CSS 처리는 어떻게 하나요?
classname 기반의 CSS가 익숙한 퍼블리셔들이 CSS-in-JS나 JSX 컴포넌트에 대한 이해도 필수로 동반되어야하는지 궁금합니다.

    박우영 · 2023년 6월 13일 5:32 오후

    안녕하세요.

    VAC에서 CSS처리는 상황에 맞게 편한 방식으로 진행하면 됩니다.

    VAC는 애초에 View 로직과 JSX를 분리해서 관리하기 때문에, JSX 개발에 대한 롤을 가진 쪽에서 관리하기 좋은 방식을 선택할 수 있습니다. 물론 어떤 방식으로 하느냐에 따라서 전체적인 개발환경에도 영향이 있기 때문에 협업할 FE 개발자와도 협의가 되어야 하겠습니다.

    개인적으로는 CSS Modules 방식을 선호하는 편인데, 별도의 css 파일로 분리해서 관리할 수도 있고, sass 같은 scss 파일을 전환해서 사용하는 것도 쉽기 때문입니다.
    물론 적용할 때 classnames 같은 모듈을 활용해서 적용할 수도 있구요.

    View 로직과 JSX 개발 롤이 따로 분리가 되어 있지 않는 환경에서는 Styled Components 같이 CSS-in-JS 방식이 직관적이고 간편한 장점이 있긴 했으나, 역할이 나눠진 환경에서는 작업이 중첩되어 후속 관리에 어려움이 있었습니다.
    다만 VAC로 분리해서 관리하는 경우 JSX롤을 가진 쪽에서 CSS-in-JS 방식이 편하다면 이 방식으로 개발을 하더라도 기존처럼 작업이 중첩되지 않기 때문에 이 방식으로 하는 것도 가능하구요.

    어떤 방식이 정답인건 아니기 때문에 자신의 상황에 맞게 기술을 선택하고 적용하면 된다고 생각합니다~
    고맙습니다.

Top 19 리 액트 디자인 패턴 The 196 Correct Answer · 2022년 12월 14일 6:10 오전

[…] Read More […]

답글 남기기

아바타 플레이스홀더

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다