You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 22:59:49