v-if와 v-show 사이에서: Vue.js 디버깅

YuJun Oh·2024년 11월 20일
0

들어가며

Vue.js를 사용하다 보면 v-ifv-show 사이에서 헷갈리게 되는 일이 종종 있습니다. 저도 그 중 한 사람으로, 오늘은 제가 v-showv-if의 차이를 제대로 이해하지 못해서 발생한 문제를 해결하기 위해 얼마나 고군분투했는지 공유하려 합니다.

"어? 분명히 코드가 맞는데 왜 안 되지?"

문제의 시작은 아주 평범했습니다. Vue 프로젝트에 jQuery를 섞어 사용하는 상황이었고, 특정 DOM 요소를 조작하려고 했습니다.

결과는?

Uncaught TypeError: $ is not a function

혹은

Cannot read properties of null (reading 'find')

"에이, 설마 jQuery를 import를 잘못했나?"라는 생각으로 한참을 삽질했죠.


문제 상황

Vue 컴포넌트에서 아래와 같은 DOM 조작을 하려 했습니다.

onMounted(() => {
  $(".templSelect-wrap").each(function () {
    const templSelect = $(this);

    templSelect.find(".sel-label").click(function () {
      templSelect.toggleClass("active");
    });
  });
});

코드는 단순했습니다. jQuery로 .templSelect-wrap이라는 클래스를 가진 DOM 요소들을 선택하고, 클릭 이벤트를 설정하려고 했습니다. 그런데 jQuery가 요소를 찾지 못해 문제가 발생했습니다.


원인 분석: DOM이 없다고?

디버깅을 시작하면서 다음 사실들을 확인했습니다.

  1. jQuery와 $가 정상적으로 로드되고 있음.
  2. Vue 컴포넌트의 mounted 훅이 정상적으로 실행되고 있음.
  3. 그런데 DOM 요소가 존재하지 않음!

Vue의 조건부 렌더링인 v-if를 사용하고 있었던 겁니다. v-if는 조건이 참일 때만 DOM을 렌더링하므로, jQuery가 DOM을 찾지 못했던 거죠.


v-ifv-show의 진실을 깨닫다

v-if

v-if는 조건이 true일 때만 DOM을 생성합니다. 초기 렌더링 시점에 DOM이 아예 존재하지 않기 때문에, jQuery 같은 외부 라이브러리로 DOM을 조작하려 하면 문제가 발생합니다.

v-show

반면, v-show는 DOM을 항상 렌더링해 두고, CSS의 display: none을 통해 보이거나 숨깁니다. DOM이 항상 존재하므로 jQuery로 조작이 가능합니다.


삽질 과정: v-if와 싸우다

1. v-if를 사용한 코드

처음 작성했던 코드는 다음과 같습니다.

<div v-if="isVisible" class="templSelect-wrap">
  <!-- 템플릿 내용 -->
</div>

여기서 isVisiblefalse일 때 DOM이 아예 렌더링되지 않으므로, jQuery가 해당 요소를 찾을 수 없었습니다.


2. v-show로 전환

문제를 해결하기 위해 v-show로 바꿨습니다.

<div v-show="isVisible" class="templSelect-wrap">
  <!-- 템플릿 내용 -->
</div>

DOM이 항상 존재했기 때문에, jQuery 코드가 정상적으로 동작했습니다.


3. Vue의 $nextTick을 활용

그런데 v-if를 써야만 하는 상황도 있었습니다. 이때는 Vue의 $nextTick을 활용하여 DOM이 렌더링된 후에 jQuery 초기화를 실행했습니다.

onMounted(() => {
  nextTick(() => {
    $(".templSelect-wrap").each(function () {
      const templSelect = $(this);

      templSelect.find(".sel-label").click(function () {
        templSelect.toggleClass("active");
      });
    });
  });
});

4. watch로 상태 변화 감지

또 다른 방법으로 watch를 사용하여 DOM이 렌더링된 시점에서 초기화를 실행할 수 있었습니다.

watch(
  () => isVisible,
  (newVal) => {
    if (newVal) {
      $(".templSelect-wrap").each(function () {
        const templSelect = $(this);

        templSelect.find(".sel-label").click(function () {
          templSelect.toggleClass("active");
        });
      });
    }
  }
);

느낀 점

Vue.js는 정말 강력하지만, 가상 DOM과 조건부 렌더링의 원리를 이해하지 못하면 이런 디버깅 지옥에 빠질 수 있습니다. 특히 외부 라이브러리(jQuery 같은)를 사용하면 DOM의 존재 여부가 중요한데, v-ifv-show의 동작 차이를 몰랐다면 지금도 헤매고 있었을 겁니다.


정리: 언제 v-ifv-show를 사용할까?

사용 상황선택이유
DOM을 동적으로 생성/제거해야 할 때v-if필요할 때만 DOM을 생성하여 성능 향상
DOM을 항상 유지해야 할 때v-showDOM이 항상 있어야 초기화 코드가 안정적으로 동작
렌더링 이후 DOM 조작이 필요한 경우v-showDOM이 존재하므로 외부 라이브러리와 충돌 없음

결론

이 사건 이후로 v-ifv-show를 무조건 교체하지 않고, 상황에 맞게 사용할 수 있게 되었습니다. 디버깅 과정을 통해 Vue.js의 렌더링 원리를 깊이 이해하게 되었고, 앞으로의 코드 작성에 큰 도움이 될 것입니다.

여러분도 비슷한 문제를 겪고 있다면, v-ifv-show의 동작 차이를 꼭 점검해 보세요! 👌


추신: 삽질은 개발자의 친구지만, 때론 조금 덜 친해도 좋겠다는 생각이 듭니다. 😅

0개의 댓글

관련 채용 정보