Vue 공부 (Essential Part)

이짜젠·2021년 12월 2일
0

Vue3 사용을 위해 공식문서를 다시한번 읽어보면서 놓쳤던 부분에 대해 정리한다.

Data Properties

정의순서

  1. created 되는 시점에 호출된다.
  2. data properties가 return한 Object를 Vue가 Vue의 Reactivity system으로 감싼다.
  3. return한 Object 는 vm의 $data의 proeprty로 노출된다.
    편의성을 위해 vm의 최상단 property로도 노출된다.

주의사항

this.$data.newProp = 1 로 새로운 data를 추가할 수 있지만, Reactivity system으로 감싸지지않았기때문에 변경시 추적은 불가능하다.


Methods Properties

주의사항

  • 화살표함수를 사용해선 안된다.
    화살표함수는 this가 없기때문에, 렉시컬컨텍스트를 따라 상위스코프의 this에 접근하게된다.
    실행시점에 Vue내부에서 this가 vm을 가르키게 되므로 반드시 함수리터럴을 이용해서 정의하도록 한다.

  • 템플릿 내부에서 사용될 경우, 순수함수로 작성하자.

  • API를 처리하는 비동기함수의 호출이 필요할 경우 라이프사이클훅에서 사용하도록 하자.

  • 템플릿 내부에서 사용되면 리렌더링의 기준이된다.
    method가 템플릿 내부에서 사용되면, method가 사용하고있는 data 가 변경되면 렌더링도 다시 이루어진다.


Computed Property

vs Method

둘은 기능상으로 완전히 동일하다.
그러나 Computed는 캐싱이된다.
즉 computed에 정의된 값들은 의존성이 있는 반응형 데이터가 변했을때만 다시 계산한다.

그렇다고 값을 return하는 함수에대해서 매번 Computed를 사용하는게 좋은 것 만은 아니다.

반응형 데이터가 변했을때만 값을 재계산 하기 때문에, 다음 computed는 매번 같은값을 return한다.

computed: {
  now() {
    return Date.now()
  }
}

Setter

computed는 따로 정의를 하지만 기본적으로 getter만 정의되지만, setter도 정의가 가능하다.

// ...
computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}
// ...

Watch

주의사항

  • 특정 데이터의 변화에 따른 다른데이터의 변화를 원할땐 watch가 아닌 computed를 사용하자. 가독성도 올라가고 cache효과도 누릴 수 있다.
  • watch는 특정데이터가 변했을때, 메소드가 호출되거나 하는 경우에만 사용하자. (비동기, API 호출등의 메소드)

vm (=ViewModel)

template에서 바인딩될 수 있는 모든 property 들은 vm의 최상단으로 노출된다.

  • data property
  • computed property
  • methods property
  • returned object of setup property

Conditional Rendering

v-if vs v-show

v-if 는 조건에 부합할대만 rendering을 한다.
v-show는 조건에 상관없이 일단 rendering을 하고, 조건에 따라 display 속성을 통해 노출/비노출 처리를 한다.

v-if with v-for

둘은 같이 사용하는것을 권하지 않는다.
만약 같이 선언이 되었다면 v-if가 먼저 계산되기떄문에 원치않는 동작이 발생할 수 있다.

v-for의 우선순위를 높이고싶다면, template 감싸 v-for를 먹인 후 내부 자식컴포넌트에서 v-if를 적용한다.

<template v-for="todo in todos" :key="todo.name">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

List Rendering

v-for와 Object

v-for의 대상은 반드시 Array일 필요는 없다.
Object의 경우 property를 순회한다.

<li v-for="(value, name) in myObject">
  {{ name }}: {{ value }}
</li>

Event Handling

동시사용

,를 이용해서 여러개의 콜백을 등록할 수 있다.

<button @click="one($event), two($event)">
  Submit
</button>

다중 이벤트 핸들러

이벤트 수정자

event.preventDefault, event.stopPropogation 과 같은 처리를 하기위해 $event를 굳이 받아서 methods 내부에서 처리되는 것 보다, methods 내부에는 비지니스 로직만 처리하고, $event와 관련된 작업은 modifer를 이용하여 콜백등록시점에 처리하는게 깔끔하다.

AS-IS

<template>
<form @submit="onSubmit($event)"></form>
</template>
// in component
methods: {
  onSubmit (event) {
    event.preventDefault();
    event.stopPropagation();
    if (event.currentTarget === event.target) {
      // ...do something
    }
  }
}

TO-BE

<template>
<form @submit.prevent.stop.self="onSubmit"></form>
</template>
// in component
methods: {
  onSubmit () {
    // ...do something
  }
}

키수정자

keyup 과 같은 이벤트에서 특정키 입력에 대한 체크를 템플릿의 선언부에서 할 수 있다.

<template>
  <!-- only call `vm.submit()` when the `key` is `Enter` -->
  <input @keyup.enter="submit" />
  
  <!-- Alt + Enter -->
  <input @keyup.alt.enter="clear" />

  <!-- Ctrl + Click -->
  <div @click.ctrl="doSomething">Do something</div>
</template>

Form Input Bindings

수정자

입력받은 데이터에 대한 trim, parseInt와 같은 처리를 쉽게 할 수 있다.

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

Component Basic

사용자정의 컴포넌트에 v-model 사용하기

사용자정의 컴포넌트에도 v-model을 사용할 수 있다.
사용자정의 컴포넌트에서는 modelValue 로 v-model 값에 접근하고, update:modelValue 로 v-model의 값을 바꿀 수 있다.

<custom-input v-model="searchText"></custom-input>
<!-- is same as --> 
<custom-input
  :model-value="searchText"
  @update:model-value="searchText = $event"
></custom-input>
app.component('custom-input', {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  template: `
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
  `
})

// or

app.component('custom-input', {
  props: ['modelValue'],
  emits: ['update:modelValue'],
  template: `
    <input v-model="value">
  `,
  computed: {
    value: {
      get() {
        return this.modelValue
      },
      set(value) {
        this.$emit('update:modelValue', value)
      }
    }
  }
})
profile
오늘 먹은 음식도 기억이 안납니다. 그래서 모든걸 기록합니다.

0개의 댓글