Vue3 如何先加载用户数据再获取关联帖子数据
解决用户数据加载完成后再获取帖子的问题
问题分析
当前代码存在几个核心问题:
useAuth未返回userData,导致组件中无法正确获取用户数据- 直接在组件初始化时调用
getPosts,此时userData.value还未加载完成,following为undefined或null useHomePosts存在命名错误(导出的函数名是useProfile而非useHomePosts)- 未处理组件卸载时的快照订阅取消,可能导致内存泄漏
解决方案步骤
1. 修复 useAuth.js
确保返回 userData,同时修正用户注销时的取消订阅逻辑:
export default function useAuth() { const userData = ref(null) const unsubscribeFromUser = ref(null) async function findUser(email) { try { const queryData = query(dbUsersRef, where('email', '==', email)) const unsubscribe = onSnapshot(queryData, (docs) => { docs.forEach((doc) => { const user = { id: doc.id, ...doc.data() } userData.value = user }) }) unsubscribeFromUser.value = unsubscribe } catch(e) { console.error(e) } } onAuthStateChanged(auth, async (user) => { if (user) { await findUser(user.email) } else { userData.value = null // 先判断订阅是否存在再执行取消 if (unsubscribeFromUser.value) { unsubscribeFromUser.value() unsubscribeFromUser.value = null } } }) // 必须返回userData才能在组件中使用 return { userData } }
2. 修复 useHomePosts.js 的命名错误
将导出的函数名改为 useHomePosts,同时确保返回 posts、getPosts 和 unsubscribeFromPosts:
export default function useHomePosts() { const posts = ref([]) const unsubscribeFromPosts = ref(null) async function getPosts(following) { // 如果following为空,直接清空posts并返回 if (!following || following.length === 0) { posts.value = [] return } try { // 先取消之前的订阅(如果存在) if (unsubscribeFromPosts.value) { unsubscribeFromPosts.value() } const queryData = query(dbPostsRef, where('username', 'in', following), orderBy('createdAt')) const unsubscribe = onSnapshot(queryData, (docs) => { const postsList = [] docs.forEach((doc) => { const post = { id: doc.id, ...doc.data() } postsList.push(post) }) // 反转数组,最新的帖子在前 posts.value = postsList.reverse() }) unsubscribeFromPosts.value = unsubscribe } catch(e) { console.error(e) posts.value = [] } } return { posts, getPosts, unsubscribeFromPosts } }
3. 修改 HomeView.vue,使用 watch 监听用户数据变化
通过监听 userData 的变化,确保在用户数据加载完成后再调用 getPosts,同时在组件卸载时取消帖子订阅:
<template> <div> <PostComponent v-for="post in posts" :key="post.id" :post="post" /> </div> </template> <script setup> import PostComponent from '@/components/PostComponent.vue' import useHomePosts from '@/composables/useHomePosts' import useAuth from '@/composables/useAuth' import { watch, onUnmounted } from 'vue' const { posts, getPosts, unsubscribeFromPosts } = useHomePosts() const { userData } = useAuth() // 监听userData的变化,当userData存在且有following列表时获取帖子 watch(userData, (newUserData) => { if (newUserData?.following) { getPosts(newUserData.following) } else { // 如果没有关注列表,清空帖子 posts.value = [] } }, { immediate: true }) // 立即执行一次,避免初始状态遗漏 // 组件卸载时取消帖子快照订阅 onUnmounted(() => { if (unsubscribeFromPosts.value) { unsubscribeFromPosts.value() } }) </script>
关键说明
- 使用
watch监听userData,确保只有当用户数据加载完成且存在following列表时,才调用getPosts - 每次调用
getPosts前先取消之前的订阅,避免重复监听导致的内存泄漏 - 组件卸载时手动取消所有快照订阅,防止内存泄漏
- 处理了
following为空的边界情况,避免数据库查询错误
内容的提问来源于stack exchange,提问作者ShedeurCoder
相关产品推荐
相关产品推荐

