[Vuejs] 동적 & 비동기 컴포넌트

grapefruit, 내용과 무관한 이미지

아래 Dynamic & Async Components 에 대한 번역글 입니다.

다음 글을 숙지 하셨다는 전제하에 설명이 진행됩니다. Components Basics. 컴포넌트에 대해 이해가 잘 되지 않으신 상태라면 링크를 따라 먼저 숙지하세요.

keep-alive with Dynamic Components

이전에는 탭 인터페이스에서 컴포넌트 간의 변경을 위해is attribute 를 사용했습니다.

<component v-bind:is="currentTabComponent"></component>

이러한 컴포넌트간의 변화가 있을 때, 때로는 컴포넌트의 상태를 유지하거나 성능상의 이유로 re-rendering 되는 것을 피하려 할 것입니다. 예를 들면, 앞의 탭 인터페이스를 약간 확장한다고 했을 때:

[캡쳐본입니다. 참고만 하세요.]

포스트 하나를 선택하고나서 Archive 탭을 누르게 되면, 다시 Posts 탭을 눌렀을 때 앞에서 선택한 포스트가 선택되어 있지 않다는 것을 알 수 있을겁니다.이는 탭을 누를 때마다 Vue 가 currentTabComponent의 새로운 인스턴스를 생성하기 때문입니다.

동적 컴포넌트를 재생성하는 것은 유용한 것이긴 하지만, 이러한 상황에서는 각각의 컴포넌트가 처음 만들어지고나서 캐시 처리 되기를 바랄지도 모릅니다. 이를 해결하기 위해 우리는 <keep-alive>요소와 함께 동적 컴포넌트를 감쌀 수 있습니다.

<!-- 비활성 컴포넌트는 캐싱! -->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>

아래 결과를 확인하세요.

[원글에서 확인하세요]

이제 Posts탭은 render 되지 않아도 상태(선택한 post)를 계속 가지고 있게 됩니다. 
전체 코드는 다음 링크에서 확인하세요. link

<keep-alive>는 컴포넌트에 name option을 가지고 있거나 , 혹은 지역/전역으로 등록되어 있는 이름이 있는 컴포넌트간에 전환되어야 합니다.

자세한 내용은 API 문서의 <keep-alive> 를 참고하세요.

Async Components

큰 응용프로그램에서는 앱을 작은 단위로 나누고 필요한 컴포넌트만 서버로부터 가져오는 것이 필요할 것입니다. 쉽게 말해서, Vue는 컴포넌트 정의를 비동기로 처리할 수 있도록 factory function 을 이용하게 해줍니다. Vue 는 컴포넌트가 render 되야 할 때와 re-render를 위해 캐시 할 때, factory function 을 실행합니다. 예를 들면,

Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// resolve callback 에 컴포넌트 정의를 넘겨줍니다
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})

factory function은 서버로부터 컴포넌트 정의를 처리할 때 실행할 resolve callback 을 받습니다. 또한 load 를 실패했을 때는 reject(reason) 로 처리 될 수 있습니다. 여기서 setTimeout 은 데모용입니다. 어떻게 컴포넌트를 가져올지는 원하는대로 해도 됩니다. 한가지 추천하는 방법은 Webpack’s code-splitting feature 와 함께 비동기 컴포넌트를 사용하는 것입니다.

Vue.component('async-webpack-example', function (resolve) {
// This special require syntax will instruct Webpack to
// automatically split your built code into bundles which
// are loaded over Ajax requests.
require(['./my-async-component'], resolve)
})

factory function 에서 Promise을 return 할 수도 있습니다. Webpack2 와 ES2015를 이용하면 다음과 같이 가능합니다.

Vue.component(
'async-webpack-example',
// The `import` function returns a Promise.
() => import('./my-async-component')
)

지역 등록을 이용할 때는 직접 Promise를 return 하는 함수를 넣을 수 있습니다.

new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})

만약에 비동기 컴포넌트를 사용하고자 하는 Browserify 사용자라면, 불행히도 제작자는 async loading 하는 것을 만들어야 합니다.( 링크 참고) 
Browserify 커뮤니티는 복잡한 응용프로그램에 도움이 될만한 작업물들을 발견했습니다. 다른 경우에는 비동기 처리가 기본 지원되는 Webpack을 사용하기를 추천합니다.

Loading State 처리

비동기 컴포넌트 factory 는 아래와 같이 object 를 return 할 수 있습니다.

const AsyncComponent = () => ({
// The component to load (should be a Promise)
component: import('./MyComponent.vue'),
// A component to use while the async component is loading
loading: LoadingComponent,
// A component to use if the load fails
error: ErrorComponent,
// Delay before showing the loading component. Default: 200ms.
delay: 200,
// The error component will be displayed if a timeout is
// provided and exceeded. Default: Infinity.
timeout: 3000
})
위와 같이처리하기 위해서는 Vue Router 2.4.0 이상을 사용해야 합니다.