[Vue] keep-alive 요약

Kyu·2019년 1월 28일
2

발표시간에 나왔던 keep-alive에 대해서 조금 찾아보았습니다.
keep-alive 는 컴포넌트를 상태를 보존할 때 사용합니다.

keep-alive는 비활성 컴포넌트 인스턴스를 파괴하지 않고 캐시한다고 합니다.
vue의 create-component.js 코드의 insert hook을 보면 아래와 같은 내용이 있습니다.

  insert (vnode: MountedComponentVNode) {
    const { context, componentInstance } = vnode
    if (!componentInstance._isMounted) {
      componentInstance._isMounted = true
      callHook(componentInstance, 'mounted')
    }
    if (vnode.data.keepAlive) {
      if (context._isMounted) {
        queueActivatedComponent(componentInstance)
      } else {
        activateChildComponent(componentInstance, true /* direct */)
      }
    }
  }

가상노드가 keepAlive인 경우 mount 여부에 따라서 queueActivateChildComponentactivateChildComponent을 호출합니다. queueActivateChildComponent는 전역 큐에 컴포넌트를 저장하고 activateChildComponent 를 호출하게 하는 함수입니다(사실 좀 더 복잡합니다).
결국에 두 분기 모두 activateChildComponent를 호출하는데, 이 함수는 activated 라이프사이클을 재귀적으로 호출하는 함수입니다.

...
const activatedChildren: Array<Component> = [];
...

export function queueActivatedComponent (vm: Component) {
  vm._inactive = false
  activatedChildren.push(vm)
}

queueActivatedComponent 자세히 보기

export function activateChildComponent (vm: Component, direct?: boolean) {
  if (direct) {
    vm._directInactive = false
    if (isInInactiveTree(vm)) {
      return
    }
  } else if (vm._directInactive) {
    return
  }
  if (vm._inactive || vm._inactive === null) {
    vm._inactive = false
    for (let i = 0; i < vm.$children.length; i++) {
      activateChildComponent(vm.$children[i])
    }
    callHook(vm, 'activated')
  }
}

반대로, 컴포넌트가 삭제될 때 호출되는 destroy hook은 아래와 같이 구현되어 있습니다.

destroy (vnode: MountedComponentVNode) {
    const { componentInstance } = vnode
    if (!componentInstance._isDestroyed) {
      if (!vnode.data.keepAlive) {
        componentInstance.$destroy()
      } else {
        deactivateChildComponent(componentInstance, true /* direct */)
      }
    }
  }

keepAlive가 아닌 경우 컴포넌트 인스턴스를 destory하고, keepAlive일 때는 deactivateChildComponent를 호출합니다. deactivateChildComponentdeactivated 라이프사이클을 재귀적으로 호출하도록 구현되어 있습니다.

export function deactivateChildComponent (vm: Component, direct?: boolean) {
  if (direct) {
    vm._directInactive = true
    if (isInInactiveTree(vm)) {
      return
    }
  }
  if (!vm._inactive) {
    vm._inactive = true
    for (let i = 0; i < vm.$children.length; i++) {
      deactivateChildComponent(vm.$children[i])
    }
    callHook(vm, 'deactivated')
  }
}

요약

keep-alive를 사용하면 컴포넌트 인스턴스가 전역 큐에 저장되고, 활성화 될 때는 기존 컴포넌트를 사용하여 activated 라이프 사이클 hook이 호출되며, 비활성화시에는 인스턴스를 소멸시키지 않고 deactivated 라이프사이클 hook이 호출되는것을 알 수 있습니다.

0개의 댓글