본문 바로가기
카테고리 없음

Vue 공식 문서 훑어보기 - 라이프사이클 · 이벤트 핸들링 · 바인딩(폼, 클래스, 스타일)

by klm hyeon woo 2024. 3. 19.

목차

· 라이프 사이클

· 이벤트 핸들링

· 클래스 바인딩

· 스타일 바인딩

· 폼 바인딩


라이프 사이클

각각의 Vue 컴포넌트 인스턴스는 생성되고, 소멸될 때 사전에 정의된 몇 단계의 과정을 거치게 되는데 이를 라이프사이클(liftcycle)이라고 합니다. 라이프사이클 훅(Lifecycle hooks)은 라이프사이클 단계에서 사용자가 자신의 코드를 추가할 수 있는 단계 별 기능(function)입니다.

Lifecycle Hooks 등록

컴포넌트가 렌더링을 완료하고 DOM 노드를 만든 후, onMounted hooks를 사용하여 코드를 실행할 수 있습니다.

import { onMounted } from 'vue';
 
export default {
    setup() {
        onMounted(() => {
            console.log("컴포넌트 mounted");
        });
    }
};

Lifecycle Hooks

컴포넌트 라이프 사이클의 각 단계에서 실행되는 함수들을 라이프사이클 훅이라고 합니다.

라이프사이클 훅에 접두사 "on"을 붙여 컴포넌트의 라이프사이클 훅에서 코드를 실행할 수 있습니다.

라이프사이클 훅은 setup() 함수 내에서 동기적으로 호출을 해야합니다.

 

Options API Composition API
beforeCreate 더 이상 필요하지 않음
created 더 이상 필요하지 않음
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeupdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated
serverPrefetch onServerPrefetch

Vue 인스턴스는 생성(create)되고, DOM에 부착(mount)되고, 업데이트(update)되며 없어지는(destory) 4가지 과정을 거치게 됩니다.

Creation(생성) → Mounting(장착) → Updating(수정) → Destruction(소멸)

Creation

컴포넌트의 초기화 단계이며 Creation Hooks는 라이프사이클 단계에서 가장 먼저 실행됩니다.

  • 아직 컴포넌트가 DOM에 추가되기 전이므로 DOM에 접근할 수 없습니다.
  • 서버 렌더링이 지원되는 단계입니다.
  • 클라이언트나 서버 렌더링 단에서 처리해야할 일이 있으면 이 단계에서 진행을 합니다.
beforeCreate

컴포넌트 인스턴스가 초기화 될 때 실행됩니다. data() 또는 computed와 같은 다른 옵션을 처리하기 전에 즉시 호출됩니다.

created

컴포넌트 인스턴스가 초기화를 완료한 후 호출되는 훅입니다.

setup

Composition API의 setup() 훅은 Options API 훅보다 먼저 호출됩니다.

beforeCreate와 created 라이프사이클 혹은 Option API에서 사용하는 라이프사이클 훅으로 Vue3 Composition API를 활용하여 개발을 진행할 때는 setup() 함수로 대체할 수 있습니다.

export default {
    beforeCreate() {
    },
    created() {
    },
    setup() {
        // etc..
    }
}

Mounting

DOM 컴포넌트를 삽입하는 단계입니다. 관련 훅으로는 onBeforeMount와 onMounted가 있습니다.

  • 서버 렌더링에서 지원되지 않습니다.
  • 초기 렌더링 직전에 돔을 변경하고자 한다면 이 단계에서 활용할 수 있습니다.
onBeforeMount

컴포넌트가 마운트되기 직전에 호출됩니다.

  • 대부분의 경우 사용을 권장하지 않습니다.
onMounted

컴포넌트가 마운트된 후에 호출되며, DOM에 접근할 수 있습니다.

  • 모든 자식 컴포넌트가 마운트되었음을 의미합니다.
  • 자체 DOM 트리가 생성되어 상위 컴포넌트에 삽입됨을 의미합니다.

Updating

반응형 상태 변경으로 컴포넌트의 DOM 트리가 업데이트 된 후 호출될 콜백을 등록합니다.

  • 디버깅이나 프로파일링 등을 위해 컴포넌트 재 렌더링 시점을 알고싶을 때 주로 사용됩니다.
onBeforeUpdate

반응형 상태 변경으로 컴포넌트의 DOM 트리를 업데이트하기 직전에 호출될 콜백을 등록합니다.

컴포넌트에서 사용되는 반응형 상태 값이 변해서, DOM에도 그 변화를 적용시켜야할 때가 있습니다.

이때, 변화 직전에 호출되는 것이 바로 onBeforeUpdate 훅입니다.

onUpdated

반응 상태 변경으로 인해 컴포넌트가 DOM 트리를 업데이트한 후에 호출됩니다.

상위 컴포넌트의 onUpdated 훅은 하위 컴포넌트의 훅 이후에 호출됩니다. (Child → Parent)

이 훅은 다른 상태 변경으로 인해 발생할 수 있는 컴포넌트의 DOM 업데이트 후에 호출됩니다.

특정 상태 변경 후에 업데이트 된 DOM에 액세스해야하는 경우 대신 nextTick()을 사용해야합니다.

* onUpdated 훅에서 컴포넌트 상태를 변경하게 되면 무한 업데이트 루프가 걸릴 수 있는 위험이 있어 공식 문서에서는 위험 사항으로 제공하고 있습니다.

Destruction

해제(소멸)단계이며 onBeforeUnmount와 onUnmounted가 있습니다.

onBeforeUnmount

컴포넌트가 마운트 해제되기 직전에 호출이 됩니다.

onUnmounted

컴포넌트가 마운트 해제된 후 호출이 됩니다.

그 밖에 다양한 라이프사이클 훅이 존재하고 있습니다.

  • onErrorCaptured()
  • onRenderTracked()
  • onRenderTriggered()
  • onActivated()
  • onDeactivated()
  • onServerPrefetch()

이벤트 핸들링

이벤트 처리는 v-on 디렉티브로 사용할 수 있습니다.

그리고 v-on 이벤트는 자주 사용하기 때문에, @ 단축 표현으로도 많이 사용됩니다.

const counter = ref(0);
<Fragement>
    <button @click="counter += 1"> counter : {{ counter }} </button>
</Fragment>

메소드 이벤트 핸들러

const printEventInfo = (event) => {
    console.log(event.target);
    console.log(event.target.tagName);
}
<div>
    <button @click="printEventInfo">printEventInfo</button>
</div>

이벤트 객체 접근

인라인 핸들링에서 event 객체에 접근할 수 있으며, 접근하는 방법은 $event 키워드를 사용합니다.

const printEventInfo = (message, event) => {
    console.log('message', message);
    console.log(event.target);
    console.log(event.target.tagName);
}
<button @click="printEventInfo("hello Vue3", $event)">
    This is inline event handler
</button>

이벤트 수식어

이벤트를 조작할 때 이벤트 내부에서 event.preventDefault() 또는 event.stopPropagation() 메서드를 호출할 수 있습니다.
메소드에서 이러한 메소드의 호출은 어렵지 않지만, 메소드 안에서 비즈니스 외에 이러한 코드는 비효율적입니다.
이 문제를 해결하기 위해 Vue는 v-on 이벤트에 다양한 이벤트 수식어를 제공합니다.

  • .stop = event.stopPropagation()
  • .prevent = event.preventDefault()
  • .capture = 캡처 모드를 사용할 때 이벤트 리스너를 사용 가능합니다.
  • .self = 오로지 자기 자신만 호출할 수 있습니다. 타깃 요소가 self일 때 발동이 됩니다.
  • .once = 해당 이벤트트 한 번만 실행이 됩니다.
  • .passive = 일반적으로 모바일 장치의 성능을 개선하기 위해 터치 이벤트 리스너와 함께 사용됩니다.
/* 클릭 이벤트 전파가 중단되었습니다 */
<a @click.stop="doThis"></a>
 
/* 제출 이벤트가 페이지를 다시 로드하지 않습니다 */
<form @submit.prevent="onSubmit"></form>
 
/* 수정자는 체이닝이 가능합니다. */
<a @click.stop.prevent="doThat"></a>
 
/* 단순히 수식어만 사용이 가능합니다 */
<form @submit.prevent></form>
 
/**
* 캡쳐 모드를 사용할 때 이벤트 리스너를 사용 가능합니다.
* 즉, 내부 엘리먼트를 대상으로 하는 이벤트가 해당 엘리멘트에서 처리되기 전에 여기서 처리합니다.
*/
<div @click.capture="doThis">...</div>
 
/**
* event.target이 엘리먼트 자체인 경우에만 트리거를 처리합니다.
* 자식 엘리먼트에서는 처리되지 않습니다.
*/
<div @click.self="doThat">...</div>
 
<div @scroll.passive="onScroll">...</div>

키 수식어

키보드 이벤트를 수신할 때 종종 특정 키를 확인해야하는 경우가 있습니다. 그래서 Vue에서는 v-on 또는 @ 디렉티브에 키 수식어를 제공합니다.

  • .enter
  • .tab
  • .delete ("Delete"와 "BackSpace" 키 모두를 수신합니다)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
<input type="text" @keyup.enter="addTodo"/>

시스템 키 수식어

아래의 수식어를 사용하여 해당 수식어 키가 눌러진 경우에만 마우스 또는 키보드 이벤트 리스너를 트리거할 수 있습니다.

  • .ctrl
  • .alt
  • .shift
  • .meta (Mac에서는 meta는 command key, windows에서 meta는 윈도우 키이며, 이는 특정 키보드마다 차이를 보입니다)
/* 알트(alt) + 엔터(enter) */
<input @keyup.alt.enter="clear"/>
 
/* 컨트롤(ctrl) + 엔터(enter) */
<input @keyup.ctrl.enter="send"/>
 
/* 컨트롤(ctrl) + 클릭(click) */
<div @click.ctrl="doSomething">Do something</div>

.exact 수식어

.exact 수식어는 정확한 조합이 눌러져야하는 것을 요구합니다.

/* 아래 코드는 알트(alt) 또는 쉬프트(shift)와 함께 눌렀을 때도 실행이 됩니다 */
<button @click.ctrl="onClick">A</button>
 
/* 아래 코드는 컨트롤(ctrl)만 눌러져 있을 때 실행이 됩니다 */
<button @click.ctrl.exact="onCtrlClick">A</button>
 
/* 아래 코드는 시스템 키가 눌리지 않는 상태인 경우에만 작동합니다 */
<button @click.exact="onClick">A</button>

그 밖의 마우스 버튼 수식어

  • .left
  • .right
  • .middle

HTML 클래스 바인딩

객체 바인딩

클래스를 동적으로 바인딩하기 위해서는 :class(v-bind:class)를 사용할 수 있습니다.

<div
    class="text"
    :class="{ active: isActive, 'text-danger': hasError }"

위의 예시처럼 v-bind:class 디렉티브는 일반 class 속성과 공존할 수 있습니다. 그리고 객체를 반환하는 computed에 바인딩을 할 수도 있습니다.

<div class="text" :class="classObject"></div>
const classObject = computed(() => {
    return {
        active: isActive.value && !hasError.value,
        'text-danger': !isActive.value && hasError.value,
    }
})

배열 바인딩

배열에 :class를 바인딩하여 클래스 목록을 적용할 수 있습니다.

const activeClass = ref('active');
const errorClass = ref('text-danger');
<div :class="[activeClass, errorClass]"></div>

인라인 스타일 바인딩

HTML style 속성에 객체 값을 바인딩 할 수 있습니다.

const activeColor = ref('red');
const fontSize = ref(30);
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

템플릿이 더 깔끔해지도록 스타일 객체에 직접 바인딩을 하는 것이 좋습니다.

const styleObject = reactive({
    color: 'red',
    fontSize: '13px'
});
<div :style="styleObject"></div>

배열 바인딩

:style은 여러 객체 배열에 바인딩 할 수 있습니다.

<div :style="[baseStyles, overridingStyles]"></div>

폼 바인딩

v-model

프론트엔드에서 입력 양식을 처리할 때 입력 요소의 상태와 자바스크립트의 상태를 동기화해야하는 경우가 많습니다.

value를 바인딩하고, @input 이벤트로 text를 변경하는 것은 번거로울 수 있습니다.

<input
    :value="text"
    @input="event => text = event.target.value"
/>

그래서 Vue에서는 이러한 작업을 단순화할 수 있도록 양방향을 바인딩할 수 있는 v-model 디렉티브를 제공합니다.

<input v-model="text"/>

textarea

  • :value, @input
<textarea
    :value="textareaValue"
    @input="(event) => (textareaValue = event.target.value)"
></textarea>
  • v-model
<textarea v-model="textareaValue"></textarea>

checkbox, radio, select

v-model은 내부적으로 HTML 요소가 어떤 요소냐에 따라 서로 다른 속성(:value)과 이벤트(@input)를 사용합니다.

  • input과 textarea는 value 속성과 input 이벤트를 사용합니다.
  • checkbox와 radio 버튼은 checked 속성과 change 이벤트를 사용합니다.
  • select 태그는 value 속성과 change 이벤트를 사용합니다.
checkbox
  • :checked, @change
<input
    type="checkbox"
    :checked="checkboxValue"
    @change="(event) => (checkboxValue = event.target.checked)"
/>
 
  • v-model
<input
    type="checkbox"
    v-model="checkboxValue"
/>
radio
  • v-model
<label>
    <input type="radio" name="type" value="O" v-model="radioValue"/>
    O형
</label>
<label>
    <input type="radio" name="type" value="A" v-model="radioValue"/>
</label>
select
  • v-model
<select v-model="selectValue">
    <option value="html">HTML 수업</option>
    <option value="css">CSS 수업</option>
    <option value="javascript">JavaScript 수업</option>
</select>

checkbox

하나의 checkbox는 단일 boolean 값을 가집니다.

<label>
    <input type="checkbox" v-model="checkboxValue"/>
    {{ checkboxValue }}
</label>

여러 개의 checkbox는 배열을 바인딩할 수 있습니다.

<div>
    <label>
        <input type="checkbox" v-model="checkboxValues" value="html"/>
        HTML   
    </label>
    <label>
        <input type="checkbox" v-model="checkboxValues" value="css"/>
        CSS
    </label>
    <label>
        <input type="checkbox" v-model="checkboxValues" value="javascript"/>
        JavaScript 
    </label>
    <p>
        {{ checkboxValues }}
    </p>
</div>

값 바인딩

체크박스에 바인딩 된 모델의 값은 기본적으로 `true`와 `false`이지만 특정 상황에서는 다른 문자로 치환해야하는 경우가 생깁니다.

이럴 경우 체크 유무를 따져 값을 직접 변경해주는 방법 이외에 `true-value`와 `false-value`와 같은 props를 사용하여 특정 값으로 바인딩이 가능합니다.

단일 checkbox일때 boolean이 아닌 다른 값으로 바인딩을 하고 싶다면 true-value, false-value 속성을 사용할 수 있습니다.

<label>
    <input
        type="checkbox"
        v-model="checkboxYN"
        true-value="Yes"
        false-value="No"
    />
    {{ checkboxYN }}
</label>

v-model 수식어

.lazy

기본적으로 v-model은 각 input 이벤트 후 입력과 데이터를 동기화 합니다. lazy 수식어를 추가하여 change 이벤트 이후에 동기화를 진행할 수 있습니다.

<input v-model.lazy="text"/>
.number

사용자 입력이 자동으로 number 타입으로 형변환 되기를 원한다면 .number 수식어를 추가하면 됩니다.

<input v-model.number="text"/>
.trim

사용자가 입력한 내용에서 자동으로 앞뒤 공백을 제거하는 트림 처리가 되길 바란다면, v-model이 관리하는 input에 trim 수식어를 추가하면 됩니다.

<input v-model.trim="text"/>

댓글