[TIL] Proxy를 이용해서 리액트와 유사한 리렌더링 로직 만들어보기

yongkini ·2023년 7월 5일
1

Today I Learned

목록 보기
142/173

동기

: Proxy에 관련해서 공부를 하다 Object를 중간에 가로채서 get, set 등의 내부 메서드를 쓸 수 있다는 것을 알게 됐고, 이 로직을 이용하면 DOM API를 통해 코딩할 때 좀더 편리하게 리렌더링 로직을 짤 수 있을 것 같아서 직접 만들어봤다.

목표

  • 이름을 입력하면 모든 ul 태그의 child를 제거하고, 새롭게 li 태그를 fragment로 묶어서 리렌더링한다.
  • 이름을 입력하면(즉, 추가하면) 총원의 숫자도 변한다.

html 코드

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h2>심해 탈출 인원</h4>
    총원 : <span id="numberSpan"></span>
    <ul id="nameUl">
      <li>test</li>
    </ul>
    VIP
    <input id="nameInput" type="text" />
    <button id="nameBtn">register</button>
    NORMAL
    <input id="normalNameInput" type="text" />
    <button id="normalNameBtn">register</button>
    <script src="./app.js"></script>
  </body>
</html>

js 코드

let dataArr = [];

// GOAL : set을 하면 리스트를 리렌더링하고 싶다.
// 이 때, react의 state를 안쓰고, Proxy를 이용하고 싶다.

const rerenderFunction = () => {
  const ulElement = document.getElementById("nameUl");
  while (ulElement.firstChild) {
    ulElement.removeChild(ulElement.lastChild);
  }
  // 먼저 전부다 날리고 -- (1)
  const fragment = new DocumentFragment();
  proxyArr.forEach((el) => {
    const liElement = document.createElement("li");
    liElement.textContent = el;
    fragment.append(liElement);
  });
  // Proxy arr를 통해 li & fragment를 구성하고 -- (2)
  ulElement.append(fragment);
  // append 한다 -- (3)
  const spanElement = document.getElementById("numberSpan");
  spanElement.textContent = proxyArr.length;
  // 마지막으로 총원의 수를 spanElement에 textContent로 심어준다. -- (4)
};

let proxyArr = new Proxy(dataArr, {
  get(target, key) {
    return target[key];
  },
  set(target, key, value) {
    if (typeof value === "string") {
      target[key] = value;
      return true;
    } else if (key === "length") {
      rerenderFunction();
      return true;
    } else {
      return false;
    }
  },
});

// 이 때, 배열의 push를 쓰면 setter가 두번 호출된다.
// https://stackoverflow.com/questions/71188314/set-trap-execute-for-two-times-js-proxy
// target=[], prop=0, val=Manuel: Adds a new value to an index
// target=["Manuel"], prop=length, val=1: Updates length of array

rerenderFunction();
const inputElement = document.getElementById("nameInput");
const btnElement = document.getElementById("nameBtn");
btnElement.addEventListener("click", function () {
  proxyArr.push(`VIP_${inputElement.value}`);
});

const normalInputElement = document.getElementById("normalNameInput");
const normalBtnElement = document.getElementById("normalNameBtn");
normalBtnElement.addEventListener("click", function () {
  proxyArr.push(normalInputElement.value);
});

// proxy를 안써도 구현할 수 있지만, proxy를 써놓으면
// 위에처럼 vip인 경우, normal인 경우 모두 하나의 object(proxy)에 그냥 세팅해주듯이 해도
// 자연스럽게 내용이 반영이 된다는 편리함?이 있는 것 같다.
// 물론 분기 처리를 하면 똑같이 proxy 없이 구현할 수 있지만
profile
완벽함 보다는 최선의 결과를 위해 끊임없이 노력하는 개발자

0개의 댓글