λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ“  archive

[Vue.js] Error Boundary 둜 μ—λŸ¬ ν•Έλ“€λ§ν•˜κΈ°

by HandHand 2022. 2. 20.

Vue μ—μ„œ Error Boundary둜 μ—λŸ¬ μ²˜λ¦¬ν•˜κΈ°

πŸ“Œ Error Boundary λž€?

이전에 잠깐 React 곡뢀할 λ•Œ 곡식 λ¬Έμ„œμ— Error Boundary λΌλŠ” 기법이 μ†Œκ°œλ˜μ–΄ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

 

Error Boundary λŠ” μ»΄ν¬λ„ŒνŠΈμ—μ„œ λ°œμƒν•œ μ—λŸ¬λ₯Ό λ‹€λ£¨λŠ” ν•˜λ‚˜μ˜ λ°©λ²•μœΌλ‘œ

μ—λŸ¬λ₯Ό μ²˜λ¦¬ν•˜λŠ” μ»΄ν¬λ„ŒνŠΈ(Error Boundary)λ₯Ό λ§Œλ“€μ–΄ μ•±μ˜ 싀행에 λ¬Έμ œκ°€ 생기지 μ•Šλ„λ‘ ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

 

Vue 에도 ν•΄λ‹Ή 기법이 μžˆμ„κΉŒ κΆκΈˆν•΄μ„œ μ°Ύμ•„λ΄€μ—ˆλŠ”λ° 이λ₯Ό μ†Œκ°œν•˜λŠ” 글이 μžˆμ–΄μ„œ μ •λ¦¬ν•΄λ΄€μŠ΅λ‹ˆλ‹€.

 

πŸ“Œ Vue μ—μ„œ Error Boundary μ‚¬μš©ν•˜κΈ°

Vue 2.5 λ²„μ „μ—μ„œλŠ” errorCaputred λΌλŠ” 훅을 μ§€μ›ν•˜κΈ° μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€.

ν•΄λ‹Ή ν›…μ—μ„œλŠ” μžμ‹ μ»΄ν¬λ„ŒνŠΈμ—μ„œ λ°œμƒν•œ μ—λŸ¬λ₯Ό 감지해 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Error Boundary λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

 

λ¨Όμ € errorCaptured 훅을 μ‚¬μš©ν•΄ Error Boundary μ»΄ν¬λ„ŒνŠΈλ₯Ό μ •μ˜ν•©λ‹ˆλ‹€.

// ErrorBoundary.vue

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  name: 'ErrorBoundary',
})
export default class ErrorBoundary extends Vue {
  private hasError = false;

  public errorCaptured () {
    this.hasError = true
  }

  public render(h: any) {
    return this.hasError ? h('li', 'something wrong') : this.$slots.default[0];
  }
}
</script>

그리고 μΌλΆ€λ‘œ μ—λŸ¬λ₯Ό λ°œμƒμ‹œν‚€λ„λ‘ λ Œλ”λ§ν•˜λŠ” 예제λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.

// CarListItem.vue

<template>
  <li>
    이름: {{ carInfo.name }}
    가격 : {{ numberWithCommas(carInfo.price) }}
  </li>
</template>

<script lang="ts">
import { Component, Vue, Prop } from 'vue-property-decorator'

@Component({
  name: 'CarListItem'
})
export default class CarListItem extends Vue {
  @Prop({ required: true }) readonly carInfo!: { id: number; name: string; price: number; }

  public numberWithCommas(x: number) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
}
</script>
// CarList.vue

<template>
  <ul>
    <template v-for="carInfo in carInfos">
      <error-boundary :key="carInfo.id">
        <car-list-item :carInfo="carInfo"  />
      </error-boundary>
    </template>
  </ul>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

import CarListItem from './CarListItem.vue'
import ErrorBoundary from './ErrorBoundary.vue'

@Component({
  name: 'CarList',
  components: { CarListItem, ErrorBoundary }
})
export default class CarList extends Vue {
  private carInfos = [
    { id: 1, name: 'a', price: null },
    { id: 2, name: 'b', price: 1232321 },
    { id: 3, name: 'c', price: 123212323 },
  ]
}
</script>

μ˜ˆμ œμ—μ„œ null 에 λŒ€ν•΄μ„œ μ •κ·œμ‹μ„ μˆ˜ν–‰ν•  수 μ—†κΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•˜κ³ ,

ErrorBoundary 덕뢄에 UI Fallback 을 지정할 수 있게 λ©λ‹ˆλ‹€.

ν™”λ©΄μ—λŠ” λ‹€μŒκ³Ό 같이 λ‚˜μ˜€κ²Œ λ©λ‹ˆλ‹€.

 

1

 

πŸ“Œ Vue μ—μ„œ μ—λŸ¬ λ°œμƒ κ·œμΉ™

Vue μ—λŠ” μ „μ—­ config.errorHandler κ°€ μ‘΄μž¬ν•˜μ—¬ λ°œμƒν•œ λͺ¨λ“  μ—λŸ¬λŠ” ν•΄λ‹Ή ν•Έλ“€λŸ¬λ‘œ 처리 κ°€λŠ₯ν•©λ‹ˆλ‹€.

이λ₯Ό 톡해 ν•œ κ³³μ—μ„œ μ—λŸ¬μ— λŒ€ν•œ μ²˜λ¦¬μ™€ 톡계등을 μˆ˜ν–‰ν•  수 μžˆκ²Œλ©λ‹ˆλ‹€.

λ§Œμ•½ errorCaptured 훅이 μ‘΄μž¬ν•œλ‹€λ©΄ λͺ¨λ“  errorCaptured 훅이 호좜되며

μ΅œμ’…μ μœΌλ‘œ config.errorHandler 에 λ„λ‹¬ν•©λ‹ˆλ‹€.

λ§Œμ•½ errorCaptured μ—μ„œ false λ₯Ό λ°˜ν™˜ν•œλ‹€λ©΄ μ—λŸ¬κ°€ μ „λ‹¬λ˜λŠ” 것을 막을 수 μžˆμŠ΅λ‹ˆλ‹€.

 

πŸ“Œ 유의 사항

DOM 이벀트 ν•Έλ“€λŸ¬

Dom 에 직접 v-on 으둜 이벀트 ν•Έλ“€λŸ¬λ₯Ό ν• λ‹Ήν•œ λ’€ ν•΄λ‹Ή ν•Έλ“€λŸ¬μ—μ„œ λ°œμƒν•œ μ—λŸ¬λŠ”

Error Boundary μ—μ„œ κ°μ§€ν•˜μ§€ λͺ»ν•˜λŠ” λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

ν•΄λ‹Ή μ΄μŠˆμ— λŒ€ν•΄μ„œ μ œμ•ˆλœ 사항이 이미 Github 에 μ‘΄μž¬ν•˜λŠ”λ°..

feat(errors): sync/async error handling for lifecycle hooks and v-on handlers (#7653, #6953) by enkot · Pull Request #8395 · vuejs/vue

 

Vue 의 μ£Όμš” 개발자 Evan You λŠ” λ‹€μŒκ³Ό 같이 λ„€ 가지 κ²½μš°μ— λŒ€ν•΄μ„œ errorCaputred λ₯Ό 톡해

μ²˜λ¦¬ν•  수 μžˆλ‹€κ³  μ–ΈκΈ‰ν–ˆμŠ΅λ‹ˆλ‹€.

  • render functions
  • watcher callbacks
  • lifecycle hooks
  • component event handlers

PR 도 μ²˜λ¦¬λ˜μ—ˆκ³  ν•΄μ„œ ν…ŒμŠ€νŠΈ ν•΄λ΄€λ”λ‹ˆ Dom 에 ν• λ‹Ήλœ 이벀트 ν•Έλ“€λŸ¬ μ—λŸ¬λŠ” errorCaptured μ—μ„œ

처리λ₯Ό λͺ»ν•˜λŠ” κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€. (이 뢀뢄은 좔가적인 확인이 ν•„μš”ν•΄λ³΄μž„)

 

ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ μ‚¬μš© μ‹œ

Vue μ—μ„œλ„ ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλΌλŠ” κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.

ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈλŠ” eager-render 되기 λ•Œλ¬Έμ— 같은 template μŠ€μ½”ν”„μ— μžˆλŠ” λ‹€λ₯Έ μ»΄ν¬λ„ŒνŠΈμ˜

errorCaptured μ—μ„œ μ—λŸ¬λ₯Ό λ°›μ•„ μ²˜λ¦¬ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

μ΄λŠ” Vue 의 ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈμ˜ 섀계 방식에 λ”°λ₯Έ 결과둜

Vue 의 ν•¨μˆ˜ν˜• μ»΄ν¬λ„ŒνŠΈ 섀계 ꡬ쑰가 λ³€κ²½λ˜μ§€ μ•ŠλŠ” 이상 λ³€ν•˜μ§€ μ•Šμ„ κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€.

 

πŸ“Œ μ°Έκ³  자료

Handling Errors in Vue with Error Boundaries

API - Vue.js

λ°˜μ‘ν˜•

πŸ’¬ λŒ“κΈ€