Single Page Application: How to unmount app in Vue.js 3 Composition API when enter/reload the app?

huangapple go评论72阅读模式
英文:

Single Page Application: How to unmount app in Vue.js 3 Composition API when enter/reload the app?

问题

Webpack服务器在浏览器控制台中显示以下警告:

> [Vue警告]:主机容器上已经存在一个应用程序实例。
如果您想在同一主机容器上安装另一个应用程序,需要首先调用app.unmount()卸载前一个应用程序。

所以,我遇到了使用以下代码的问题:

app.unmount()

main.js


// 导入方法和组件。
import { createApp} from 'vue';
import router from './router';
import App from './App.vue';

// 创建Vue应用程序。
const app = createApp(App);

// 安装所需的实例,如插件、组件和指令。
app.use(router);

// 将'App.vue'作为根组件挂载。
app.mount('#app');

App.vue


<template>

 <div>
    <div id="header">Hello world</div>

    <div id="main">
    
        <router-view name="default" v-slot="{ Component, route }">

          <div v-if="errMsg" class="container mt-3">
            <h2 class="text-center">
              {{ errMsg }}
            </h2>
          </div>

          <div v-else>
            <component :is="Component"
                       :key="route.meta.usePathKey ? route.path : undefined">

            </component>
          </div>
    
        </router-view>
    
    </div>
  </div>

</template>

<script>
import {ref, onErrorCaptured} from 'vue';

export default {
  name: "App",
}
</script>

<script setup>

// 常量、函数和生命周期钩子
const errMsg = ref(null);

onErrorCaptured(() => {
  errMsg.value = "Something went wrong!";
});

</script>

<style>

</style>

注意

1- 我不能在main.js中直接使用app.unmount()

2- 不能使用Vue生命周期钩子像onUnmounted(),因为应该只在setup()脚本内使用。

3- 不能从App.vue中卸载app(没有意义)。

英文:

Webpack server is showing the following warning in browser console :

> [Vue warn]: There is already an app instance mounted on the host container.
If you want to mount another app on the same host container, you need to unmount the
previous app by calling app.unmount() first.

So, I'm facing an issue with proper use of:

app.unmount()

main.js


// Import methods and component.
import { createApp} from &#39;vue&#39;;
import router from &#39;./router&#39;;
import App from &#39;./App.vue&#39;;

// Create vue App.
const app = createApp(App);

// Install the required instances like plugin, component and directive.
app.use(router);

// Mount &#39;app&#39; const (App.vue) as root component.
app.mount(&#39;#app&#39;);

App.vue


&lt;template&gt;

 &lt;div&gt;
    &lt;div id=&quot;header&quot;&gt;Hello world&lt;/div&gt;

    &lt;div id=&quot;main&quot;&gt;
    
        &lt;router-view name=&quot;default&quot; v-slot=&quot;{ Component, route }&quot;&gt;

          &lt;div v-if=&quot;errMsg&quot; class=&quot;container mt-3&quot;&gt;
            &lt;h2 class=&quot;text-center&quot;&gt;
              {{ errMsg }}
            &lt;/h2&gt;
          &lt;/div&gt;

          &lt;div v-else&gt;
            &lt;component :is=&quot;Component&quot;
                       :key=&quot;route.meta.usePathKey ? route.path : undefined&quot;&gt;

            &lt;/component&gt;
          &lt;/div&gt;
    
        &lt;/router-view&gt;
    
    &lt;/div&gt;
  &lt;/div&gt;

&lt;/template&gt;

&lt;script&gt;
import {ref, onErrorCaptured} from &#39;vue&#39;;

export default {
  name: &quot;App&quot;,
}
&lt;/script&gt;

&lt;script setup&gt;

// constants, functions and life-cycle hooks
const errMsg = ref(null);

onErrorCaptured(() =&gt; {
  errMsg.value = &quot;Something went wrong!&quot;;
});

&lt;/script&gt;

&lt;style&gt;

&lt;/style&gt;

Note

1- I can't use app.unmount() in main.js directly and

2- can't use Vue life-cycle hooks like onUnmounted() because should only use inside setup() script.

3- can't unmount app from App.vue (nonsense).

答案1

得分: 0

以下是翻译好的部分:

解决方案,我应该查看app(App.vue)是否已经挂载,这是有用的:

1- 当刷新页面时,这样您就不需要像Webpack服务器建议的那样再次挂载另一个app实例。

2- 将防止触发在App.vue<script setup>中定义的方法两次(一次用于组件的更新生命周期,第二次在重新挂载组件时触发,这在刷新页面时会发生)。

main.js


// 导入方法和组件。
import { createApp } from 'vue';
import router from './router';
import App from './App.vue';

let app = "";
let containerSelector = "#app";

// 检查app是否已经挂载
const mountPoint = document.querySelector(containerSelector);

if (mountPoint && mountPoint.__vue_app__ !== undefined) {

    // 将现有挂载点设置为'app'。
    app = mountPoint.__vue_app__._instance.proxy;
}
else {

    // 创建一个新的app实例
    app = createApp(App);
    
    // 安装所需的实例,如插件、组件和指令。
    app.use(router);

    // 将'app'(App.vue)挂载为根组件。
    app.mount(containerSelector);
}

如果您不想使用现有的app实例,您可以通过在if{}块内使用app.unmount()并删除else{}块中的代码,然后在条件块之外添加您的组件、存储等,以新创建的app实例并在最后进行挂载。

英文:

The solution, I should see if app (App.vue) is already mount, it's useful:

1- When refresh the page, so you don't need to mount another app instance as Webpack server suggest in the warning.

2- Will prevent trigger the methods these defined in App.vue &lt;script setup&gt; twice (one for update life-cycle of component and second when re-mount the component again, which happens when refresh the page).

main.js


// Import methods and component.
import { createApp} from &#39;vue&#39;;
import router from &#39;./router&#39;;
import App from &#39;./App.vue&#39;;


let app = &quot;&quot;;
let containerSelector = &quot;#app&quot;;

// check if app has been mounted already
const mountPoint = document.querySelector(containerSelector);

if (mountPoint &amp;&amp; mountPoint.__vue_app__ !== undefined) {

    // Set the existing mount point to &#39;app&#39;.
    app = mountPoint.__vue_app__._instance.proxy;
}
else {

    // create a new app instance
    app = createApp(App);
    
    // Install the required instances like plugin, component and directive.
    app.use(router);

    // Mount &#39;app&#39; (App.vue) as root component.
    app.mount(containerSelector);
}

If you don't want to use the existing app instance, you can change the code by use app.unmount() inside if{} block and remove else{} block, then outside the condition block plug in your components, stores..etc to the new created app instance and mount it at the end.

huangapple
  • 本文由 发表于 2023年5月14日 21:18:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76247680.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定