본문으로 건너뛰기
홈
기술
기술 전체
프로그래밍68
컴퓨터 과학63
AI48
웹 개발36
인프라33
데이터31
소프트웨어 공학18
소개
← 목록으로웹 개발 › 프론트엔드 › Vue

v-if 조건문

목차

v-if 조건문

주문 목록을 요청하는 화면에는 로딩 중, 실패, 빈 목록, 조회 성공이라는 서로 다른 상태가 있다. 각 상태에 별도의 불리언을 두면 loading과 failed가 동시에 참이 되는 조합을 관리해야 한다. 작은 화면에서는 하나의 status와 v-if 분기를 사용해 어떤 상태에서 어떤 UI를 만드는지 드러낼 수 있다.

이 글의 실행 예제는 Vue 2의 new Vue 문법을 사용한다. Vue 2는 지원이 종료됐으며, 아래 내용은 기존 프로젝트의 동작을 이해하기 위한 예제다. 지원 종료 안내

하나의 상태에 하나의 화면 연결하기

다음 코드는 서버 없이 화면 분기를 관찰하는 데모다. 버튼을 눌러 응답 상태를 직접 바꾼다.

<div id="app">
  <button type="button" @click="status = 'loading'">로딩</button>
  <button type="button" @click="status = 'error'">오류</button>
  <button type="button" @click="showEmpty">빈 결과</button>
  <button type="button" @click="showOrders">주문 표시</button>

  <p v-if="status === 'loading'" role="status">주문을 읽고 있습니다.</p>
  <p v-else-if="status === 'error'" role="alert">주문을 불러오지 못했습니다.</p>
  <p v-else-if="orders.length === 0">등록한 주문이 없습니다.</p>
  <ul v-else>
    <li v-for="order in orders" :key="order.id">{{ order.name }}</li>
  </ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
<script>
new Vue({
  el: '#app',
  data: { status: 'loading', orders: [] },
  methods: {
    showEmpty() {
      this.orders = [];
      this.status = 'success';
    },
    showOrders() {
      this.orders = [{ id: 42, name: '키보드 주문' }];
      this.status = 'success';
    }
  }
});
</script>

로딩 버튼을 누르면 로딩 문단이 렌더링된다. 주문 표시 버튼을 누르면 앞의 세 조건이 모두 거짓이 되어 마지막 목록이 나타난다. v-else-if와 v-else는 바로 앞 조건 요소와 이어져야 한다. 사이에 관계없는 <div>를 끼워 넣으면 하나의 조건 연쇄로 읽히지 않는다.

예제의 마지막 v-else는 앞의 조건에 걸리지 않는 모든 상태를 받는다. 실제 코드에 idle, cancelled 등을 추가한다면 기본 분기로 흘려보낼지, 명시적인 조건을 둘지도 결정해야 한다. 상태 값을 늘리고 템플릿을 그대로 두면 예상하지 못한 화면이 나올 수 있다.

조건을 바꾸면 DOM에 무슨 일이 생기는가

v-if는 요소의 존재를 제어한다. 처음부터 거짓이면 해당 분기의 하위 컴포넌트를 생성하지 않는다. 참이 되어 만들어진 분기를 다시 거짓으로 바꾸면 그 안의 컴포넌트는 해제된다. 해당 컴포넌트 안에만 저장한 입력 상태나 타이머도 생명주기와 함께 고려해야 한다.

flowchart LR
    F[조건 false] -->|true로 변경| M[요소와 컴포넌트 생성]
    M -->|false로 변경| U[컴포넌트 해제]
    U -->|다시 true| R[새 인스턴스 생성]

반면 v-show는 요소를 렌더링한 상태에서 CSS의 display를 바꾼다. 숨긴 동안에도 컴포넌트 인스턴스와 내부 상태가 남는다. 조건부 렌더링 공식 설명

관찰할 것v-ifv-show
처음 거짓인 경우분기 내부 생성 지연요소 생성 후 숨김
반복 전환생성·해제 비용 발생주로 표시 스타일 변경
자식의 로컬 상태해제 후 새로 시작할 수 있음인스턴스 유지
용도 예드물게 여는 무거운 편집기자주 여닫는 작은 패널

표만 보고 항상 어느 하나가 빠르다고 결정할 수는 없다. 패널 초기화 비용, 전환 빈도, 숨겨진 상태에서 계속 실행되는 작업을 함께 살펴본다. v-show로 숨긴 차트가 여전히 타이머를 돌고 있다면 화면에서 안 보인다고 작업이 멈춘 것은 아니다.

여러 요소를 묶고 입력 상태를 제어하기

제목과 설명 두 요소를 한꺼번에 분기하려면 불필요한 래퍼를 추가하지 않고 <template v-if="...">를 사용할 수 있다. v-show에는 <template>을 같은 방식으로 적용하지 않는다. 실제로 표시 스타일을 바꿀 요소가 필요하기 때문이다.

Vue 2는 같은 종류의 요소를 재사용할 수 있다. 서로 다른 로그인 방식에서 입력값을 의도적으로 초기화하려면 입력에 다른 key를 준다.

<template v-if="loginMode === 'email'">
  <label for="email">이메일</label>
  <input id="email" key="email-login" v-model="email">
</template>
<template v-else>
  <label for="username">사용자 이름</label>
  <input id="username" key="username-login" v-model="username">
</template>

loginMode, email, username은 모두 data에 먼저 선언한다. 요소를 새로 생성하는 것과 모델 값을 비우는 것은 별개의 결정이다. 위 코드는 두 모델을 보존하므로 이메일 모드로 돌아오면 email에 남아 있는 값이 다시 표시된다. 완전한 초기화를 원하면 상태도 명시적으로 초기화한다.

목록 필터와 접근 권한을 혼동하지 않기

같은 요소에 v-if와 v-for를 함께 쓰면 우선순위를 알아야 읽을 수 있고 Vue 버전 전환 때도 문제가 생긴다. 목록 전체를 숨길 때는 부모에 조건을 두고, 일부 항목만 보일 때는 computed로 필터링한 배열을 반복한다. 이렇게 나누면 조건의 대상이 목록인지 개별 행인지 명확해진다.

또한 관리자 버튼을 v-if="isAdmin"으로 숨겼다고 권한 검사가 끝난 것은 아니다. 브라우저 상태와 요청은 사용자가 바꿀 수 있다. 실제 데이터 조회·변경 권한은 서버에서 검증하고, 조건부 렌더링은 허용된 기능을 사용자에게 보여 주는 역할로 사용한다.

같은 카테고리의 글