Subscribe on changes!

Lifecycle hooks is executed in the wrong order.

avatar
Aug 2nd 2023

Vue version

3.3.4

Link to minimal reproduction

https://stackblitz.com/edit/vitejs-vite-avbi9v?file=src%2FApp.vue

Steps to reproduce

  1. Click the open:0 button
  2. Click the close button
  3. Click the open:1 button

What is expected?

Console log:

open: 0
init             => onBeforeMount
onBeforeMount    => onMounted
onMounted        => onBeforeUnmount
onBeforeUnmount  => onUnmounted
close
init             => onBeforeMount
onBeforeMount    => onMounted
open: 1
init             => onBeforeMount
onBeforeMount    => onMounted
onMounted        => onBeforeUnmount
onBeforeUnmount  => onUnmounted

OR:

open: 0
close
init             => onBeforeMount
onBeforeMount    => onMounted
open: 1

What is actually happening?

Console log:

open: 0
init             => onBeforeMount
onBeforeMount    => onBeforeUnmount
onBeforeUnmount  => onMounted
onMounted        => onUnmounted
close
init             => onBeforeMount
onBeforeMount    => onMounted
open: 1
init             => onBeforeMount
onBeforeMount    => onBeforeUnmount
onBeforeUnmount  => onMounted
onMounted        => onUnmounted

System Info

System:
    OS: macOS 13.4.1
    CPU: (8) arm64 Apple M1
    Memory: 83.78 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 16.19.1 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 8.19.3 - /opt/homebrew/bin/npm
    pnpm: 8.4.0 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 115.0.5790.114
    Safari: 16.5.1

Any additional comments?

In this demo, Item's lifecycle hooks are sometimes executed in this order: onBeforeMount->onBeforeUnmounted->onMounted->onUnmounted

avatar
Aug 7th 2023

There is a unit test to ensure the order is correct. It can be found below:

https://github.com/vuejs/core/blob/3be4e3cbe34b394096210897c1be8deeb6d748d8/packages/runtime-core/__tests__/apiLifecycle.spec.ts#L216

I'm uncertain how to reconcile your reproduction case with this. Something maybe wrong with your test case - I wouldn't expect onBeforeUnmount to be called at all when you click open.

avatar
Aug 10th 2023

The key point in reproducing the problem is effectiveVisible

Change modelRef.value?.effectiveVisible to visible.value can fix the demo:

const effectiveList = computed(() => list.value.filter(it => !visible.value || it !== selectedItem.value))

Console will print:

open: 0
close
init             => onBeforeMount
onBeforeMount    => onMounted
open: 1
avatar
Dec 14th 2023

same problem: element-plus#15145

avatar
Dec 14th 2023

Note: The Item.vue component was unmounted during the mounting phase. IMO, the onMounted hook should not be executed because the component was not actually successfully mounted. This is the same reason as #9264. Maybe fixed by #9370 see demo base on #9370