※ 일본의 한 블로그 글을 번역한 포스트입니다. 오역 및 의역, 직역이 있을 수 있으며 틀린 내용은 지적해주시면 감사하겠습니다.
Suspense이란?
비동기 처리가 해결되기까지 폴 백 컨텐츠 (예를 들어 Loading중 아이콘)을 표시해주는 특별한 컴포넌트이다. 지금까지는 v-if = "loading === true" 등의 상태 변수를 사용하여 제어한 것을 상태 변수를 사용하지 않고 간략하게 쓸 수 있게 해준다.
Suspense의 작성법
아래와 같이 <Suspense> 컴포넌트로 감싸서 내부의 <template #default>내에 비동기 컴포넌트를 <template #fallback>내에, 그 비동기 컴포넌트가 해결 될 때까지에 나타낼 것 (폴 백 컨텐츠)을 기재한다. 이러한 작성으로, 간략하게 비동기 컴포넌트의 처리가 해결 될 때 까지의 폴 백 컨텐츠를 구현할 수 있다.
이 코드는 <AsyncComponents>의 비동기 처리가 끝날 때 까지, loading...이라는 문자열을 표시해준다.
<Suspense>
<template #default>
<AsyncComponents/>
</template>
<template #fallback>
loading...
</template>
</Suspense>
Suspense의 샘플 구현
샘플로서 이 GIF와 같이 비동기처리를 가다리는 동안에 Loading 표시를하는 컨포넌트를 만들보았다.
1. 비동기 컴포넌트를 작성
먼저 비동기처리를 하는 컴포넌트를 만든다. User 데이터를 API로 부터 획득해서 User이름의 리스트를 표시하는 동작을 상정하고 있다.
포인트는 setup() 함수에서 async/await를 사용해 Promise를 반환하는 부분이다. 이것으로 비동기 컴포넌트로서 Suspense에서의 대기 대상이 된다.
<template>
<ul>
<li v-for="(user, i) in users" :key="i">{{ user }}</li>
</ul>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
async setup() {
// API리퀘스트의 mock 2000ms후에 유저명 배열이 반환
const fetchUsers = () => {
return new Promise<string[]>(resolve => {
setTimeout(() => {
resolve(['Jon', 'Bob', 'Nancy'])
}, 2000)
})
};
// 유저명을 획득
// setup()내에서 읽어 들이고 있으므로 Vue.js 2계에서 말하는 onCreated()와 동일한 라이프 사이클로 실시하고 있다.
const users = await fetchUsers();
return {
users
}
}
});
</script>
2. Suspense 이용하는 쪽의 컴포넌트
다음은 Suspense 이용하는 쪽의 컴포넌트를 작성하고 있다. 비동기 컴포넌트를 <Suspense>의 <template #default> 내에 기재하여, <template #fallback>내에 비동기 처리ㄹ가 해결될 때 가지 나타내고 싶은 Loading...를 기재하고 있다.
이 코드로 비동기 처리를 대기하는 간 Loading을 표시하는 것이 가능해진다.
<template>
<img src="./logo.png">
<h1>Suspense demo</h1>
<Suspense>
<template #default>
<AsyncUsers/>
</template>
<template #fallback>
Loading...
</template>
</Suspense>
</template>
<script lang="ts">
import { ref, defineComponent, onErrorCaptured, Ref } from 'vue'
import AsyncUsers from "./components/AsyncUsers.vue"
export default defineComponent({
components: {
AsyncUsers
},
setup() {}
})
</script>
여러 개의 비동기 컴포넌트를 가지고 있는 경우
Suspense가 특히 효과를 발휘하는 곳이 여러 개의 비동기 컴포넌트를 가지고 있는 경우이다. 구현은 굉장히 간단하다. <Suspense> 태그 내에 처리를 기다리고 싶은 비동기 컴포넌트를 나열하면 그만이다.
모든 비동기 컴포넌트가 해결 될 때까지 폴 백 컨텐츠를 화면에 표시해준다.
<Suspense>
<template #default>
<AsyncUsers/>
<AsyncFoods/>
<AsyncAnimals/>
</template>
<template #fallback>
Loading...
</template>
</Suspense>
에러 바인딩
API 리퀘스트라고 한다면 에러 바인딩이 필요하게 된다. Suspense를 사용하는 경우의 에러 바인딩은 Vue3.0에 새롭게 추가된 라이브 사이클 훅 onErrorCaptured로 간략하게 쓸 수 있다.
아래는 AsyncUsers에서 발생한 에러를 onErrorCaptured로 캐치해서 에러 메시지를 표시하는 예이다.
<template>
<div class="container">
<img src="./logo.png">
<h1>Suspense demo</h1>
<div v-if="error">
{{ error }}
</div>
<Suspense>
<template #default>
<AsyncUsers>
</template>
<template #fallback>
Loading...
</template>
</Suspense>
</div>
</template>
<script lang="ts">
import {defineComponent, onErrorCaptured, ref, Ref} from 'vue'
import AsyncUsers from "./components/AsyncUsers.vue"
export default defineComponent({
components: {
AsyncUsers,
},
setup() {
const error: Ref<any> = ref(null);
onErrorCaptured(e => {
error.value = e;
return true;
});
return {
error
}
}
})
</script>
AsyncUsers에서 reject(500에러)가 발생한 경우 위 코드라면 다음과 같이 표시된다.
참고자료
https://qiita.com/ryo2132/items/7225d60768a15dabfb9f
'IT > 언어' 카테고리의 다른 글
[SCSS] SCSS의 mixin 기초 (0) | 2023.08.20 |
---|---|
[Vue3] Vue3 베이스의 밸리데이션 프레임워크 VeeValidate(v4) (0) | 2023.08.17 |
[Java] 정규표현 (0) | 2023.07.26 |
[JavaScript] Blob의 사용법 (0) | 2023.07.21 |
[Junit] static 메소드의 Mock화 (0) | 2023.07.11 |