개발새발 로그

MVC패턴을 이해하고, 리액트에서 사용해보자 본문

React

MVC패턴을 이해하고, 리액트에서 사용해보자

이즈흐 2025. 2. 9. 00:09

📖들어가며..

MVC패턴이 무엇이고,

MVC패턴으로 어떻게 설계하며

MVC패턴으로 어떻게 리액트에 적용하는지 알아보려고한다.

 

 


1. MVC패턴 규칙

  1. 모델은 컨트롤러나 뷰에 의존하면 안된다.
    1. 모델 내부에 컨트롤러 및 뷰와 관련된 코드가 있으면 안된다.
  2. 뷰는 모델에만 의존해야 하고, 컨트롤러에는 의존하면 안된다.
    1. 뷰 내부에 모델의 코드만 있을 수 있고, 컨트롤러의 코드가 있으면 안된다.
  3. 뷰가 모델로부터 데이터를 받을 때는 사용자마다 다르게 보여주어야 하는 데이터에 한해서만 받아야 한다.
  4. 컨트롤러는 모델과 뷰에 의존해도 된다.
    1. 컨트롤러 내부에는 모델과 뷰의 코드가 있을 수 있다.
  5. 뷰가 모델로부터 데이터를 받을 때는 반드시 컨트롤러에서 받아야 한다.

MVC를 보면서 개인적으로 느꼈던 궁금증

🚀 View가 데이터를 받아 보여줄 때 무조건 Controller를 거쳐서 데이터를 받아야하나?

  • 의존성 증가 (결합도 상승)
    • View가 Model을 직접 참조하면, Model의 내부 구현이 변경될 때 View도 수정해야 한다.
    • 결과적으로 View와 Model이 강하게 결합되면서 코드가 복잡해지고 유지보수가 어려워진다.
  • 비즈니스 로직과 UI의 분리 어려움
    • Model의 데이터를 단순히 읽어오는 것처럼 보여도, 데이터를 가져오는 과정에서 변환이 필요할 수 있다.
    • 이런 변환(예: 데이터 필터링, 정렬)은 Controller나 특정 서비스에서 처리하는 것이 맞다.
  • 테스트와 재사용성이 어려워짐
    • View에서 Model을 직접 사용하면, 특정한 데이터 의존성이 생겨서 테스트가 어려워진다.
    • View를 재사용하려고 할 때, Model을 함께 수정해야 하는 경우가 발생할 수 있다.

- 하지만 "뷰가 모델로부터 데이터를 받을 때는 사용자마다 다르게 보여주어야 하는 데이터에 한해서만 받아야 한다." 을 보면 Model에 접근해 데이터를 보여줄 수 있다.

 

🚀 그럼 카테고리 목록과 같은 상수 데이터들도 Model에 저장해서 사용해야 하나?

굳이 관리할 필요 없다

 

🚀 Controller를 통해 가져온 Model 데이터를 View에 보여줄 때, useState에 저장해야 할까?

 정답: 경우에 따라 다르지만, 보통 useState에 저장하는 것이 좋다.


❌ useState 없이 getData()를 직접 호출하는 방식의 문제점

function ViewComponent() {
  const data = getData(); // 데이터를 직접 가져옴 (비효율적)

  return <div>{data.name}</div>;
}

📌 문제점

  1. 컴포넌트가 리렌더링될 때마다 getData()가 계속 실행됨
    → 성능 저하 발생 (특히 API 호출 시)
  2. 비동기 데이터 처리 어려움
    → getData()가 비동기 함수라면, UI가 처음에는 undefined 상태가 될 수도 있음.
  3. 상태 관리 어려움
    → useState 없이 getData()를 직접 사용하면, 데이터가 변경될 때 자동으로 View가 업데이트되지 않음.

✅ useState를 사용하여 데이터를 관리하는 방식 (올바른 방식)

function ControllerComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    getData().then((result) => setData(result));
  }, []);

  return <ViewComponent data={data} />;
}

function ViewComponent({ data }) {
  if (!data) return <p>Loading...</p>;

  return <div>{data.name}</div>;
}

📌 장점
리렌더링 시 불필요한 데이터 요청 방지 (useState에 저장된 값을 사용)
비동기 데이터 처리가 쉬움 (useEffect를 사용해 한 번만 실행)
데이터 변경 시 자동 UI 업데이트

 

 

🚀 MVC 패턴에서 Controller를 통해 가져온 데이터가 비동기가 아니지만 변경이 잦다면, useState에 저장하는 것이 옳을까?

📌 결론:
View에서 UI 업데이트가 필요하다면 → useState에 저장
View에서 UI 업데이트가 필요 없으면 → const 또는 useRef 사용

 


개인적으로 설계한 MVC패턴

1. View에서 이벤트가 일어난다

2. 이벤트에 해당하는 변경을 위해 Controller는 Model에서 주어지는 CRUD로 데이터를 변경한다.

3. Model값이 변경되면 View가 업데이트 되어야하는데 read만 하는 데이터라면 Model에서 직접 가져온다

4. 아니라면 Controller를 거쳐서 가져온다.

 

현재는 ContextProvider를 사용했다.

 

근데 여기서 read만 하는 데이터라면 Model에서 직접 가져온다 부분에서 이것이 옳은 것인가? 생각하게 되었다.

이를 정리하기 위해 아래에서 추가적으로 해당 내용을 적어보았다.

 

 

 


그럼 실제 리액트에서는 어떻게 코드를 작성했는지 간단한 예시로 보자

 

1. Model 구축하기

먼저 ModelProvider를 만든 후 위처럼 필요한 모델들을 만들었다.

 

그리고 위처럼 Model에 접근할 수 있도록 CRUD를 만들어주면 된다.

결과적으로 Model과 CRUD 메서드를 Provider로내려주는 것이다.

 

🤔CRUD 메서드를 모두 만들어놔야하나요?

이때 CRUD는 사용하지않아도 무조건 만들어 놓는 것이 좋다.

언젠가는 요구사항이 추가되어 사용하게 될 메서드들이기 때문이다.

 

🤔Create와 Update가 헷갈려요

 

CREATE와 UPDATE의 차이

단일 데이터를 다루는 경우 CREATE와 UPDATE는 다음과 같은 차이가 있다.

CREATE 데이터가 없으면 새로 삽입하고, 존재하면 덮어씌울 수도 있음 (UPSERT 형태)
UPDATE 기존 데이터가 존재할 때만 값을 변경
REPLACE 기존 데이터를 삭제 후 새 데이터로 대체

즉,

  • CREATE데이터가 없으면 새로 만들고, 존재하면 특정 정책(덮어씌우기 등)에 따라 동작.
  • UPDATE기존 데이터가 반드시 존재해야 하고, 특정 필드만 수정하는 경우가 많다.
  • REPLACE기존 데이터를 완전히 삭제하고 새 데이터를 삽입하는 방식

그래서 위처럼 CREATE 메서드가 추가되고, 덮어씌울수 있도록 함수를 만들어줘야한다.

그러면 신경써야할 것은 배열과 같은 데이터에서 덮어씌울 때 중복되지 않도록 해야하는 것이다.

그래서 나는 위처럼 Set을 활용해서 중복되지않도록 구성했다.

 

2. Controller 구축하기

Controller에서는 아까 Model에서 만든 CRUD 메서드를 가져와서 필요한 로직들을 만든다.

예를들어 아래처럼 만들 것이다.

이처럼 Controller에서는 Model에 접근해서 Model의 데이터를 수정한다.

그리고 이렇게 만든 메서드들을 View에서 사용할 수 있도록 Provider로 내려주는 것이다.

 

 

3. View에서 Controller 사용하기

View에서는 위처럼 useContext를 이용해 Controller에서 만든 메서드를 가져온다.

그러면 해당 메서드를 통해 Model을 변경할 것이고, Model이 변경되면 해당 변경사항을 View에 알려주는 것이다.

 

🤔이때 View에는 어떻게 알려야할까?

처음에 나는 단지 Read를 하는 것이니까 Model에 직접 접근해서 읽어와도 되지않을까? 생각했다.

뷰가 모델로부터 데이터를 받을 때는 사용자마다 다르게 보여주어야 하는 데이터에 한해서만 받아야 한다.

위 규칙에 따르면 계속해서 사용자에 의해 변하는 데이터라면 직접 읽어와도 된다는 뜻인 것 같았다.

 

하지만 이 또한 설계에서 갈리게 된다.

🤔만약 View에서 Model에 접근하지 못하도록 한다면 어떻게 해야할까?

단순히 Controller에서 Model의 데이터를 가져오는 Get 메서드를 만들면 된다.

🤔그럼 Model의 데이터가 변경됐을 때 View에 잘 반영되려면 어떻게 해야할까?

아마도 이런식으로 구성할 것이라고 예상된다.

 


 

현재는 Context API를 사용했지만 

원래라면 Redux와 같은 상태관리 라이브러리를 사용해서 렌더링이 최소화 되도록 해야할 것이다.

 

예를 들어 Redux로 설계한다면 MVC 방법으로 설계한다 했을 때 위와 비슷한 설계가 될 것이다.

다만 중요한 것은 View에서 Model의 데이터를 어떻게 읽어오느냐 일 것이다.

Redux에서는 Model의 데이터를 바로 읽어올 수 있는 메서드가 존재하기 때문이다(useSelector)

이를 Controller에서 get해오는 메서드를 만들고, 이 메서드만을 사용하게끔 약속하는 것이 중요한 점일 것이다.

 

 


 

📘마치며..

이렇게 간단하게 MVC패턴으로 리액트 예시를 들어 적용해보았다.

처음에는 어떻게 설계해야하지 막막했지만

각 MVC의 역할과 규칙에 이해가 쌓이면서 어떻게 설계해야할지 감을 잡게 되었다.

 

 

728x90
반응형
LIST