'How to prevent double invoking of the hook created?

So I have a problem with my vue3 project. The gist: I need to support different layouts for some use cases: authorization, user profile's layout, group's layout, etc. I've got the opportunity by this way:

  1. Create a component AppLayout.vue for managing layouts
<template>
    <component :is="layout">
        <slot />
    </component>
</template>

<script>
import AppLayoutDefault from "@/layouts/EmptyLayout";

import { shallowRef, watch } from "vue";
import { useRoute } from "vue-router";
export default {
    name: "AppLayout",
    setup() {
        const layout = shallowRef(AppLayoutDefault);
        const route = useRoute();
        watch(
            () => route.meta,
            async (meta) => {
                try {
                    const component =
                        await require(`@/layouts/${meta.layout}.vue`);
                    layout.value = component?.default || AppLayoutDefault;
                } catch (e) {
                    layout.value = AppLayoutDefault;
                }
            }
        );
        return { layout };
    },
};
</script>
  1. So my App.vue started to look so
<template>
    <AppLayout>
        <router-view />
    </AppLayout>
</template>
  1. To render a specific layout, I've added to router's index.js special tag meta
 {
    path: '/login',
    name: 'LoginPage',
    component: () => import('../views/auth/LoginPage.vue')
 },
 {
    path: '/me',
    name: 'MePage',
    component: () => import('../views/user/MePage.vue'),
    meta: {
      layout: 'ProfileLayout'
    },
  },
  1. Now I can create some layouts. For example, I've made ProfileLayout.vue with some nested components: Header and Footer. I use slots to render dynamic page content.
<template>
<div>
    <div class="container">
        <Header />
        <slot />
        <Footer />
    </div>
</div>
</template>

So, when I type the URL http://example.com/profile, I see the content of Profile page based on ProfileLayout. And here the problem is: Profile page invokes hooks twice.

I put console.log() into created() hook and I see the following Log of the components creating

That's problem because I have some requests inside of hooks, and they execute twice too. I'm a newbie in vuejs and I don't understand deeply how vue renders components. I suggest that someting inside of the code invokes re-rendering and Profile Page creates again. How to prevent it?



Solution 1:[1]

Your profile page loaded twice because it's literally... have to load twice. This is the render flow, not accurate but for you to get the idea:

  1. Your layout.value=AppDefaultLayout. The dynamic component <component :is="layout"> will render it first since meta.layout is undefined on initial. ProfilePage was also rendered at this point.
  2. meta.layout now had value & watcher made the change to layout.value => <component :is="layout"> re-render 2nd times, also for ProfilePage

So to resolve this problem I simply remove the default value, the dynamic component is no longer need to render default layout. If it has no value so it should not render anything.

  <keep-alive>
    <component :is="layout">
      <slot />
    </component>
  </keep-alive>
import { markRaw, shallowRef, watch } from "vue";
import { useRoute } from "vue-router";


export default {
  name: "AppLayout",
  setup() {
    console.debug("Loaded DynamicLayout");
    const layout = shallowRef()
    const route = useRoute()

    const getLayout = async (lyt) => {
      const c = await import(`@/components/${lyt}.vue`);
      return c.default;
    };

    watch(
      () => route.meta,
      async (meta) => {
        console.log('...', meta.layout);
        try {
          layout.value = markRaw(await getLayout(meta.layout));
        } catch (e) {
          console.warn('%c Use AppLayoutDefault instead.\n', 'color: darkturquoise', e);
          layout.value = markRaw(await getLayout('EmptyLayout'));
        }
      }
    );
    return { layout }
  },
};

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 8bu