Happhee.dev 2023. 2. 22. 17:05

✨ MVC 란...?

Model , View, Controller 의 약자로, 하나의 애플리케이션을 구성할 때 3가지 역할로 구분해놓은 패턴이다.

전체적인 플로우는 다음 순서와 같다.

  1. 사용자는 애플리케이션과 상호작용한다.
  2. controller의 이벤트 핸들러가 작동한다.
  3. controller는 model에게 data를 요구하고, 그 결과를 view로 전달한다.
  4. view는 data를 사용자에게 보여준다.

✨ 구조

MVC 흐름

📍Model

웹페이지에서 필요한 데이터들을 가지며, 데이터를 처리하는 곳이다.

Javascript 객체, 서버의 API 데이터, 서버에 있는 DB 등등이 가능하다.

📍View

view는 HTML 페이지 이다.

HTML 페이지에서 다양한 데이터를 수집하고, 어떠한 비즈니스 로직 또한 가지고 있으면 안된다.
즉, 컨트롤러와 모델의 정보를 알 수 없다.

뷰가 업데이트되는 방법은 총 3가지이다.

  1. Model을 이용하여 직접 업데이트
  2. Model에서 View에서 직접 알려서 업데이트
  3. View가 Polling을 주기적으로 Model의 변경을 감지하여 업데이트

 

📍Controller

사용자의 행동을 처리하는 곳이다.

사용자가 데이터를 클릭하고 수정하는 것을 포함한 이벤트들을 처리하는 것이다.
더불어 Controller는 여러 개의 view를 선택할 수 있는 1 : N 구조이지만, 단지 선택만 진행할 뿐...! 직접 업데이트를 하지는 않는다.

 

 

예를 들면 ... !
사용자가 로그인을 하기 위해서 이메일과 비밀번호를 입력하고 로그인 버튼을 누르게 된다면

  1. 로그인에 대한 요청을 controller에게 전달
  2. controller는 이메일과 비밀번호를 상태로 갖는 User라는 model을 사용
  3. model은 해당 정보를 가지고, 로그인여부를 판단하기 위해 DB에 접근
  4. 결과를 controller에게 전달
  5. controller는 결과를 보여주기 위한 view를 선택
  6. view는 controller에게 데이터를 화면에 담아 사용자에게 보여주기

총 6단계를 거치게 된다.


🖥 직접 적용해보기

기본 HTML 파일을 먼저 만들어준다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>JS MVC</title>
    <link rel="stylesheet" href="style.css" />
  </head>

  <body>
    <div class="root-wrapper">
      <button type="button" id="addBtn">CSeo Study</button>

      <ul></ul>
    </div>
    <script src="./main.js"></script>
  </body>
</html>

👇 JS 파일에서는 model에 저장되어있는 데이터를 보여주고 버튼이벤트를 통해 controller 동적으로 li태그를 추가하고, view로 사용자에게 보여준다.

const model = {
  items: [1, 2],
  lastID: 2,
};

const controller = {
  add() {
    const id = ++model.lastID;
    model.items.push(id);
    view.render();
  },

  remove(id) {
    const index = model.items.indexOf(parseInt(id));

    if (index >= 0) {
      model.items.splice(index, 1);
      view.render();
    }
  },

  getItems() {
    return model.items;
  },

  init() {
    view.init();
  },
};

const view = {
  init() {
    const addButton = document.getElementById("addBtn");

    addButton.addEventListener("click", controller.add);

    this.list = document.getElementsByTagName("ul")[0];

    this.list.addEventListener("click", (e) => {
      const itemID = e.target.parentNode.dataset.id;
      controller.remove(itemID);
    });

    this.render();
  },

  render() {
    const items = controller.getItems();

    this.list.innerHTML = "";

    items.forEach((item) => {
      const li = document.createElement("li");
      li.textContent = item;
      li.dataset.id = item;

      const removeButton = document.createElement("button");
      removeButton.className = "remove-item";
      removeButton.textContent = "X";

      li.appendChild(removeButton);
      this.list.appendChild(li);
    });
  },
};

controller.init();

실행 영상

🌈 정리

가장 단순하여 보편적으로 많이 사용되는 패턴이고, 각 기능별로 모듈화를 하여 파일이 따로 존재하기 때문에 우선 동시다발적인 개발이 가능하다.
다만, View와 Model사이의 의존성이 높아 유지보수가 어려워질 수도 있다.


📚 참고자료