-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async Component - Resolve Component + Child Page Property #15035
Comments
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 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 However, there's good news in your case - 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)]);
};
},
}); |
You are the man @danielroe 👌 . This solved my first problem, but the second one is sadly still present. |
I can't reproduce your second issue: https://stackblitz.com/edit/github-vga5kg-vv1onx. I'll happily have a look if you can provide a reproduction. |
Yeah, i'm also trying to reproduce the issue on stackblitz, but sadly it just occours on the frontend package of my monorepo. And thank you very much again for your efforts and your time |
Ideally I would like a minimal reproduction, even if it's not a stackblitz. |
Mhhhh, maybe you can see the problem from the screenshots and the The funny thing is, the error only occurs when i route to the page. If i load it via direct url call or F5, the error don't occur. [id].ts import { PermissionID, User } from '@authelion/common';
import { useToast } from 'vue-toastification';
import { NuxtLink } from '#components';
import { defineNuxtComponent, navigateTo, useRoute } from '#app';
import {
definePageMeta, resolveComponent, useAPI,
} from '#imports';
import { LayoutKey, LayoutNavigationID } from '~/config/layout';
export default defineNuxtComponent({
async setup() {
definePageMeta({
[LayoutKey.NAVIGATION_ID]: LayoutNavigationID.ADMIN,
[LayoutKey.REQUIRED_LOGGED_IN]: true,
[LayoutKey.REQUIRED_PERMISSIONS]: [
PermissionID.USER_EDIT,
PermissionID.USER_ROLE_ADD,
PermissionID.USER_ROLE_EDIT,
PermissionID.USER_ROLE_DROP,
],
});
const items = [
{
name: 'General', icon: 'fas fa-bars', urlSuffix: '',
},
{
name: 'Permissions', icon: 'fas fa-user-secret', urlSuffix: 'permissions',
},
{
name: 'Roles', icon: 'fa-solid fa-user-group', urlSuffix: 'roles',
},
];
const toast = useToast();
const handleUpdated = () => {
toast.success('The user was successfully updated.');
};
const handleFailed = (e) => {
toast.warning(e.message);
};
const nuxtPage = resolveComponent('NuxtPage');
const route = useRoute();
let entity : User;
console.log(route.params.id);
try {
entity = await useAPI()
.user
.getOne(route.params.id as string, { fields: ['+email'] });
} catch (e) {
return navigateTo({ path: '/admin/roles' });
}
console.log(entity);
return () => h('div', [
h('h1', { class: 'title no-border mb-3' }, [
h('i', { class: 'fa fa-user me-1' }),
entity.name,
h('span', { class: 'sub-title ms-1' }, [
'Details',
]),
]),
h('div', { class: 'mb-2' }, [
h(
'ul',
{ class: 'nav nav-pills' },
items.map((item) => h('li', { class: 'nav-item' }, [
h(
NuxtLink,
{
class: 'nav-link',
to: `/admin/users/${entity.id}/${item.urlSuffix}`,
},
{
default: () => [
h('i', { class: `${item.icon} pe-1` }),
item.name,
],
},
),
])),
),
]),
h('div', [
h(nuxtPage, {
onUpdated: handleUpdated,
onFailed: handleFailed,
entity,
}),
]),
]);
},
}); [id]/index.ts import { User } from '@authelion/common';
import { PropType } from 'vue';
import {
defineNuxtComponent, definePageMeta, resolveComponent,
} from '#imports';
import { LayoutKey } from '~/config/layout';
export default defineNuxtComponent({
props: {
entity: {
type: Object as PropType<User>,
required: true,
},
},
emits: ['updated', 'failed'],
async setup(props, { emit }) {
definePageMeta({
[LayoutKey.REQUIRED_LOGGED_IN]: true,
});
const handleUpdated = (e) => {
emit('updated', e);
};
const handleFailed = (e) => {
emit('failed', e);
};
const form = resolveComponent('UserForm');
const passwordForm = resolveComponent('UserPasswordForm');
return () => h('div', { class: 'row' }, [
h('div', { class: 'col-7' }, [
h('h6', { class: 'title' }, ['General']),
h(form, {
entity: props.entity,
realmId: props.entity.realm_id,
onUpdated: handleUpdated,
onFailed: handleFailed,
}),
]),
h('div', { class: 'col-5' }, [
h('h6', { class: 'title' }, ['Password']),
h(passwordForm, {
id: props.entity.id,
onUpdated: handleUpdated,
onFailed: handleFailed,
}),
]),
]);
},
}); For some reason, the child component is already rendered before, the parent async call in the parent component is terminated, and the passed entity property is therefore not avaialable and is not passed to the child component. |
Ah, likely that is because when you switch routes there's a moment when it's not resolved. You should set |
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 |
@danielroe any news on that ? |
It would be really great if a required prop by a child page is not present, that the component is not rendered at all, instead of being rendered two times, one time undefined and one time with the actual value 🙁 |
solved by v3.4.1 🎉 |
Environment
Windows_NT
v16.17.0
3.0.0-rc.11
0.5.4
npm@8.4.1
vite
css
,alias
,vite
,runtimeConfig
,modules
@nuxtjs/google-fonts@^3.0.0-0
,@pinia/nuxt@^0.4.2
-
Reproduction
[id].ts
[id]/index.ts
Describe the bug
There are actually two problems.
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:
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
The text was updated successfully, but these errors were encountered: