英文:
nuxt3: how to access fetched data in page middleware
问题
我正在处理一个Nuxt 3项目,关于我的一个文件中的语法问题有一个疑问。
(我想让它更加SEO友好,所以不使用pages/posts/[id].vue
,而是使用pages/posts/[id]/[title].vue
。)
以下是pages/posts/[id]/[title].vue
的setup
部分的代码:
type Post {
title: string;
};
const route = useRoute();
const { data } = await useFetch(
`/posts/${route.params.id}`
) as {
data: Ref<Post>
};
definePageMeta({
middleware: [
(to: RouteLocationNormalized, from: RouteLocationNormalized) => {
// 我想在这里访问获取到的数据
if (to.params.title !== data.value.title) {
navigateTo(`/posts/${data.value.id}/${data.value.title}`);
}
}
]
});
然而,当我运行代码时,我收到一个**500
错误,消息是"data is not defined."** 我知道我可以在中间件中独立获取帖子数据,但这会导致重复请求,这不是理想的情况。
我该如何改进我的代码,使其工作并且只发送一次请求?
非常感谢任何人的帮助!
英文:
I'm working on a Nuxt 3 project, and I have a question about the syntax in one of my files.
(I want to make it more SEO-friendly, so instead of using pages/posts/[id].vue
, I'm using pages/posts/[id]/[title].vue
.)
Here's the code in the setup
section of pages/posts/[id]/[title].vue
:
type Post {
title: string;
};
const route = useRoute();
const { data } = await useFetch(
`/posts/${route.params.id}`
) as {
data: Ref<Post>
};
definePageMeta({
middleware: [
(to: RouteLocationNormalized, from: RouteLocationNormalized) => {
// I want to access the fetched data here
if (to.params.title !== data.value.title) {
navigateTo(`/posts/${data.value.id}/${data.value.title}`);
}
}
]
});
However, when I run the code, I receive a 500
error with the message "data is not defined." I know that I can fetch the post data in middleware independently, but it would result in duplicate requests, which is not ideal.
How can I improve my code to make it works and send the request only once?
Thanks a lot for anyone helps!
答案1
得分: 1
你需要存储数据,我对Nuxt还很陌生,今天也有同样的问题,不过我刚刚找到了解决方法。
在你的中间件中:
const $store = useNuxtApp()
$store.$requestData = data.value
然后,在你的页面中:
<script setup>
const $store = useNuxtApp()
console.log('data', $store.$requestData)
const data = $store.$requestData;
</script>
当然,我对Nuxt(或JS框架一般)还很陌生,如果有更好的解决方案,欢迎提出,以防我漏掉了什么。
英文:
You'll need to store the data, I'm new to Nuxt and had the same question today and ended up figuring out a few minutes ago.
In your middleware:
const $store = useNuxtApp()
$store.$requestData = data.value
Then, in your page:
<script setup>
const $store = useNuxtApp()
console.log('data', $store.$requestData)
const data = $store.$requestData;
</script>
Of course I'm still very new to Nuxt (or JS frameworks in general), and any better solution would be welcome, in case I'm missing something here.
答案2
得分: 0
Here is the translated content:
使用[@joelod的答案](https://stackoverflow.com/a/76357173/10519069)和以下内容:
- [Reddit中的讨论:**在SSR中使用Pinia与Firebase Composable**](https://stackoverflow.com/a/76357173/10519069)
- [GitHub问题:**nuxtApp.call**](https://github.com/nuxt/nuxt/issues/14805#issue-1549639017)
这是解决方案:
```js
import { useNuxtApp, callWithNuxt } from '#app';
// 在中间件中只获取一次帖子数据,而不是在外部获取
definePageMeta({
middleware: [
async (to: RouteLocationNormalized, from: RouteLocationNormalized) => {
const nuxtApp = useNuxtApp();
const { data: post } = await useFetch(
`/posts/${to.params.id}`
) as {
data: Ref<Post>;
};
await callWithNuxt(
nuxtApp,
() => {
nuxtApp.$requestData = post.value;
}
);
}
]
});
const nuxtApp = useNuxtApp();
const route = useRoute();
const post: Ref<Post> = ref(nuxtApp.$requestData as Post);
if (to.params.title !== post.value.title) {
navigateTo(`/posts/${post.value.id}/${post.value.title}`);
}
// 然后你可以在任何地方使用`post`数据
useSeoMeta({
title: `${post.value.title} | My Blog`,
});
PS:
在中间件之外编写navigateTo()
可能是更好的做法,因为当useFetch
收到错误时,例如404 Not Found
或429 Too Many Requests
,如果navigateTo()
在中间件内部,则页面可能会出现[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function
的错误消息,因为你的template
可能会使用post
数据。
<details>
<summary>英文:</summary>
With [@joelod's answer](https://stackoverflow.com/a/76357173/10519069) and the followings:
- [the discuss in reddit: **USing Pinia with firebase composable in SSR**](https://stackoverflow.com/a/76357173/10519069)
- [the GitHub issue: **nuxtApp.call**](https://github.com/nuxt/nuxt/issues/14805#issue-1549639017)
Here is the solution:
```js
import { useNuxtApp, callWithNuxt } from '#app';
// fetch the post data only once in middleware instead of the outside
definePageMeta({
middleware: [
async (to: RouteLocationNormalized, from: RouteLocationNormalized) => {
const nuxtApp = useNuxtApp();
const { data: post } = await useFetch(
`/posts/${to.params.id}`
) as {
data: Ref<Post>
};
await callWithNuxt(
nuxtApp,
() => {
nuxtApp.$requestData = post.value;
}
);
}
]
});
const nuxtApp = useNuxtApp();
const route = useRoute();
const post: Ref<Post> = ref(nuxtApp.$requestData as Post);
if (to.params.title !== post.value.title) {
navigateTo(`/posts/${post.value.id}/${post.value.title}`);
}
// then you can use the `post` data anywhere
useSeoMeta({
title: `${post.value.title} | My Blog`,
});
PS:
Writing navigateTo()
outside of the middleware may be a better practice because when useFetch
received an error, such as 404 Not Found
or 429 Too Many Requests
, the page could get [nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function
if navigateTo()
is inside of the middleware, since your template
may use the post
data.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论