---
title: 동적 & 비동기 컴포넌트
type: guide
order: 105
---
> 이 페이지는 여러분이 이미 [컴포넌트 기초](components.html)를 읽었다고 가정하고 쓴 내용입니다. 컴포넌트가 처음이라면 기초 문서를 먼저 읽으시기 바랍니다.
## `keep-alive` 동적 컴포넌트
초기에는, 탭 인터페이스에서 컴포넌트들을 전환하기 위해서 `is` 특성을 사용했습니다. :
{% codeblock lang:html %}
{% endcodeblock %}
컴포넌트들을 전환할 때 가끔 성능상의 이유로 상태를 유지하거나 재-렌더링을 피하길 원할 수 있습니다. 예를 들면, 탭 인터페이스를 약간 확장 할 때 :
{% raw %}
{% endraw %}
게시물을 선택하고, _Archive_ 탭으로 전환하고, 다시 *Posts*로 전환할 때, 선택했던 게시물이 더는 보이지 않는 것 알아차릴 수 있습니다. 그 이유는 매번 새로운 탭을 선택할 때, Vue는 `currentTabComponent`의 새로운 인스턴스를 생성하기 때문입니다.
동적 컴포넌트를 재생성하는 것은 보통은 유용한 동작입니다. 하지만 이 경우에는, 탭 컴포넌트 인스턴스가 처음 생성될 때 캐시 되는 것을 선호합니다. 이런 문제를 해결하기 위해서, 동적 컴포넌트를 `` 엘리먼트로 둘러쌀 수 있습니다. :
```html
```
아래 결과를 확인하세요. :
{% raw %}
{% endraw %}
이제 _Posts_ 탭은 (게시물이 선택된) 상태를 유지할 수 있고 다시 렌더링하지도 않습니다. 완성된 코드는 [this fiddle](https://jsfiddle.net/chrisvfritz/Lp20op9o/)에서 볼 수 있습니다.
``가 컴포넌트에서 `name` 옵션을 사용하거나 로컬/글로벌 등록을 하여 정의된 모든 것들로 전환되고 있는 컴포넌트들을 요구한다는 것에 유의하세요.
더 자세한 내용은 [API reference](../api/#keep-alive)에서 `` 항목을 확인해주세요.
## 비동기 컴포넌트
커다란 어플리케이션의 경우, 앱을 작은 조각들로 나누어 두고 필요한 경우에만 서버로부터 필요한 컴포넌트를 로드해야 할 수 있습니다. 이런 작업을 쉽게 할 수 있도록 Vue는 팩토리 함수를 이용해 컴포넌트를 비동기적으로 정의하는 것을 허용합니다. Vue는 컴포넌트가 필요할 때 팩토리 함수를 실행하고 미래를 위해 결과를 캐시합니다. 예를 들어:
```js
Vue.component("async-example", function(resolve, reject) {
setTimeout(function() {
// 컴포넌트 정의를 resolve 콜백을 통해 전달
resolve({
template: "
I am async!
"
});
}, 1000);
});
```
위의 예에서 보다시피 팩토리 함수는 `resolve` 콜백을 받습니다. 콜백은 서버에 컴포넌트의 정의를 요청했을 때 호출됩니다. 물론 `reject(reason)` 을 호출하여 로딩이 실패한 경우에 대응할 수도 있습니다. setTimeout은 예제일 뿐이며, 컴포넌트를 어떻게 받아올지는 원하는 방식을 선택하면 됩니다. 권장되는 접근 방식으로써, [Webpack's code-splitting feature](https://webpack.js.org/guides/code-splitting/) 와 함께 비동기 컴포넌트를 사용하는 패턴이 있습니다:
```js
Vue.component("async-webpack-example", function(resolve) {
// 아래의 특별한 'require' 문법은
// 웹팩이 Ajax를 통해 로드한 번들들을 이용해
// 코드를 자동으로 분할하도록 합니다.
require(["./my-async-component"], resolve);
});
```
팩토리 함수 안에서 `Promise`를 반환할 수도 있습니다. Webpack 2와 ES2015 문법을 이용해 아래와 같이 쓸 수 있습니다:
```js
Vue.component(
"async-webpack-example",
// `import` 함수는 Promise를 반환합니다.
() => import("./my-async-component")
);
```
[local registration](components-registration.html#Local-Registration)을 이용하면, `Promise`를 반환하는 함수를 직접 작성할 수도 있습니다:
```js
new Vue({
// ...
components: {
"my-component": () => import("./my-async-component")
}
});
```
만약에 Browserify를 이용해서 비동기 컴포넌트를 구현하고자 하는 경우, 불행히도 Browserify를 만든 개발자가 "비동기 컴포넌트는 Browserify가 지원할 계회기 전혀 없는 것이다" 라고 이야기했다는 사실을 알아야 합니다. ([made it clear](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224))
Browserify 커뮤니티는 이미 존재하는 복잡한 예제에 대한 [대안](https://github.com/vuejs/vuejs.org/issues/620)을 찾긴 했습니다. 가능한 모든 시나리오에 대해 비동기를 완벽히 지원하는 웹팩을 이용하는 것을 권장합니다.
### Handling Loading State
> 2.3.0+ 에서 추가
비동기 컴포넌트 팩토리는 아래와 같은 포맷으로 오브젝트를 반환할 수도 있습니다:
```js
const AsyncComponent = () => ({
// 로드 할 컴포넌트(Promise여야 합니다.)
component: import("./MyComponent.vue"),
// 비동기 컴포넌트가 로딩중일 때 사용할 컴포넌트
loading: LoadingComponent,
// 비동기 컴포넌트 로딩이 실패했을 때 사용할 컴포넌트
error: ErrorComponent,
// 로딩 컴포넌트를 보여주기 전의 지연시간. (기본값: 200ms)
delay: 200,
// 초과되었을 때 에러 컴포넌트를 표시할 타임아웃. (기본값: 무한대)
timeout: 3000
});
```
> 위에 작성된 문법을 라우터 컴포넌트에 사용하기 위해서는 2.4.0+ 버전의 [Vue Router](https://github.com/vuejs/vue-router) 를 사용해야 한다는 것을 기억하세요!