Subscribe on changes!

在setup中,用插件的方式调用组件且使用了生命周期时,会得到一个警告

avatar
Aug 9th 2022

Vue version

@3.2.24

Link to minimal reproduction

https://codepen.io/mgsod/pen/ZExjYWx?editors=0000

Steps to reproduce

  • 在生命周期钩子函数前以插件的方式调用组件
createApp({
  setup() {
    vant.Dialog.alert();

    onMounted(() => {
      console.log();
    });
    return {
      message: "Hello Vue"
    };
  }
}).mount("#app");

上述代码执行时,控制台会得到如下警告

[Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement. at <App>

通过调试发现,vant以插件形式调用组件时,是通过createApp实例化后调用mount()挂载到body上。问题就在这个mount(),如果不执行mount()则不会发出警告.下面是vant插件调用组件的部分代码 https://github.com/vant-ui/vant/blob/dev/packages/vant/src/utils/mount-component.ts#L41

export function mountComponent(RootComponent: Component) {
  const app = createApp(RootComponent);
  const root = document.createElement('div');

  document.body.appendChild(root);

  return {
    instance: app.mount(root),
    unmount() {
      app.unmount();
      document.body.removeChild(root);
    },
  };
}

目前有以下两种方式可以解决这个问题:

  • 将生命周期函数提前,根据警告提示,只需要把生命周期函数提前即可
const { createApp, onMounted } = Vue;
createApp({
  setup() {
+    onMounted(() => {
+      console.log();
+    });
    vant.Dialog.alert();
-    onMounted(() => {
-      console.log();
-    });
    return {
      message: "Hello Vue"
    };
  }
}).mount("#app");
  • 给生命周期函数传入第二个参数,currentInstance
- const { createApp, onMounted } = Vue;
+ const { createApp, onMounted ,getCurrentInstance} = Vue;

createApp({
  setup() {
+    const currentInstance = getCurrentInstance()
    vant.Dialog.alert();
    onMounted(() => {
      console.log();
-    });
+    },currentInstance);
    return {
      message: "Hello Vue"
    };
  }
}).mount("#app");

What is expected?

期望:

  • 不希望得到该警告(虽然生产环境下不会发出该警告),因为我并没有使用asyncsetup

What is actually happening?

实际上:

  • 控制台得到一个警告

[Vue warn]: onMounted is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(), make sure to register lifecycle hooks before the first await statement.

System Info

System:
    OS: macOS 11.2.3
    CPU: (8) arm64 Apple M1
    Memory: 237.22 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.17.0 - ~/.nvm/versions/node/v14.17.0/bin/node
    Yarn: 1.22.17 - ~/.nvm/versions/node/v14.17.0/bin/yarn
    npm: 6.14.13 - ~/.nvm/versions/node/v14.17.0/bin/npm
  Browsers:
    Chrome: 104.0.5112.79
    Safari: 14.0.3
  npmPackages:
    vue: ^3.2.24 => 3.2.24

Any additional comments?

No response

avatar
Aug 9th 2022

Hi, thanks for your interest but Github issues are for bug reports and feature requests only. You can ask questions on the forum, the Discord server or StackOverflow.


You likely need to move the alert to an onMounted() hook:

onMounted(() => {
      console.log();
      vant.Dialog.alert();
    });
avatar
Aug 9th 2022

Hi, thanks for your interest but Github issues are for bug reports and feature requests only. You can ask questions on the forum, the Discord server or StackOverflow.

You likely need to move the alert to an onMounted() hook:

onMounted(() => {
      console.log();
      vant.Dialog.alert();
    });

实际上的情况要比这个稍微复杂一点,比如在http请求中统一管理loading状态,请求前打开loading,请求结束后关闭loading

function httpGet() {
  Loading.show()
  return new Promise(resolve => {
    // some code...
    Loading.hide()
  })
}

export default {
  setup() {
    httpGet()
    onMounted(() => {})
  }
}

这样也会得到上面的警告

avatar
Jan 17th 2023

我也遇到了这个问题,我自己封装了一个vue组件上传到了npm,当在项目中引入时也会有类似的警告,导致加载组件挂载不成功。 我调试vite打包后的dist目录文件,发现setup方法内的 onMounted方法并未执行。 image

avatar
Apr 13th 2023

我也遇到了 怎么解决呢

avatar
Apr 13th 2023

@ddmy
image 也报错了

avatar
Apr 13th 2023

我也遇到了这个问题,我自己封装了一个vue组件上传到了npm,当在项目中引入时也会有类似的警告,导致加载组件挂载不成功。 我调试vite打包后的dist目录文件,发现setup方法内的 onMounted方法并未执行。 image

已经解决了,问题原因是因为 插件依赖的VUE版本和项目的VUE版本不一致导致的。