question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Async Component - Resolve Component + Child Page Property

See original GitHub issue

Environment


  • Operating System: Windows_NT
  • Node Version: v16.17.0
  • Nuxt Version: 3.0.0-rc.11
  • Nitro Version: 0.5.4
  • Package Manager: npm@8.4.1
  • Builder: vite
  • User Config: css, alias, vite, runtimeConfig, modules
  • Runtime Modules: @nuxtjs/google-fonts@^3.0.0-0, @pinia/nuxt@^0.4.2
  • Build Modules: -

Reproduction

[id].ts

import { defineNuxtComponent, navigateTo, useRoute } from '#app';
import { resolveComponent } from '#imports';

export default defineNuxtComponent({
    async setup() {
        const entity = await /** some async api call **/
        const nuxtPage = resolveComponent('NuxtPage');

        return () => h('div', [
            h('div', [
                h(nuxtPage, {
                    entity,
                }),
            ]),
        ]);
    },
});
;

[id]/index.ts

import { defineNuxtComponent, navigateTo, useRoute } from '#app';
import { resolveComponent } from '#imports';

export default defineComponent({
    props: {
        entity: {
            type: Object,
            required: true,
        },
    },
    setup(props) {
        console.log(props.entity); 
        /** component is renedered two times. First time with null value and second time with the actual value **/
   })
});

Describe the bug

There are actually two problems.

  1. Resolve Component: The resolveComponent method is not working in an async setup function, but in a normal one it is. So it is not possible to resolve the NuxtPage Component. The error code in the console is the following one:
runtime-core.esm-bundler.js:38 [Vue warn]: resolveComponent can only be used in render() or setup().
  1. Child Page Property When i created an extra Component which is a wrapper for the NuxtPage component, which is just passing the $attr object to the NuxtPage component, i got around the first problem, because i am now able to import the wrapper component directly via an import statement. The child page component is rendered two times and the first time with null property values and the second time with the actual value. In the reproduction section it is for example the entitiy property.

Additional context

No response

Logs

No response

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:1
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
danielroecommented, Sep 27, 2022

The issue here is that Vue (and Nuxt) need synchronous access to the context. If you have an async setup, then you need to ensure that any functions that need access to the context - such as resolveComponent - should be before your first await.

Normally, Vue (and Nuxt) perform some transforms to allow you to access the context after await. However, for a setup function, this only works within <script setup> blocks - see vue documentation.

However, there’s good news in your case - resolveComponent can also be called within your render function.

Here’s some code that hopefully explains the issue:

import { defineComponent, resolveComponent } from '#imports';

export default defineComponent({
  async setup() {
    await Promise.resolve();
    // this will fail (and print a warning) as there is no accessible context
    resolveComponent('NuxtPage');

    return () => {
      // this will succeed as render functions are synchronous
      // and it is specifically designed to be called in a render function
      const nuxtPage = resolveComponent('NuxtPage');

      return h('div', [h(nuxtPage)]);
    };
  },
});
0reactions
tada5hicommented, Sep 27, 2022

Yeah i already worked around that, before like that, but that felt so wrong… and it was kinda annoying to repeat that in each child page.

// ...
setup(props) {
        // todo: remove this when this is fixed in vue/nuxt
        if (!props.entity) {
            return () => h('div', []);
        }

       // ......
},
// ....

Thank you for the reference ☺️ ✌️

PS: Non related question: Do you know how disable the notice for definePageMeta in the setup routine? I did not found another way to pass meta tags for the vue router.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Vue Async Components: Props and Testing | by Nora Brown
How to test and pass props to asynchronously-loaded (async) components' Loading and Error counterparts. Basic usage of Vue's async ...
Read more >
3 Ways to Pass Async Data to Angular 2+ Child Components
Solution 2: Use ngOnChanges ... ngOnChanges is a lifecycle hook that run whenever it detects changes to input properties. That means it's ...
Read more >
Async Components - Vue.js
As you can see, defineAsyncComponent accepts a loader function that returns a Promise. The Promise's resolve callback should be called when you have...
Read more >
Async Components in Vue 3 - This Dot Labs
Async components are best used in medium to large apps. When an app is formed out of several hundred components, it's wise not...
Read more >
How to bind angular async data to child component input ...
I added a constructor for the AppComponent class definition, that will wait on the promise to resolve and put the return values into...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found