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

如何在Pinia Store中正确使用useFirebaseAuth?

在Pinia Store中集成VueFire与Firebase Authentication的问题

在Pinia Store中结合VueFire使用Firebase Authentication时,若在Store外部执行const auth = useFirebaseAuth()获取Auth实例,会触发警告:inject() can only be used inside setup() or functional components.;调用signInWithEmailAndPassword等Firebase Auth方法时,还会出现错误:Cannot read properties of undefined (reading 'app') at signInWithEmailAndPassword。

用户原代码如下:

import { defineStore } from 'pinia'
import router from '../router/index'
import { useFirebaseAuth } from 'vuefire'
import { signOut, createUserWithEmailAndPassword, signInWithEmailAndPassword } from 'firebase/auth'

const auth = useFirebaseAuth()

export const useUserStore = defineStore('UserStore', {
    state: () => {
        return {
            user: {},
            isLoggedIn: false,
            email: '',
            password: '',
            repassword: '',
            errorMessage: '',
        }
    },
    actions: {
        async register() {
            if (this.password === this.repassword) {
                await createUserWithEmailAndPassword(auth, this.email, this.password)
                    .then((userCredential) => {
                        const user = userCredential.user
                        console.log(user)
                        router.push('/:placeName')
                    })
                    .catch((error) => {
                        const errorCode = error.code
                        console.log(errorCode)
                        this.errorMessage = error.message
                        alert(this.errorMessage)
                    })
            } else {
                alert('Passwords must match')
            }
        },
        async login() {
            await signInWithEmailAndPassword(auth, this.email, this.password)
                .then((userCredential) => {
                    const user = userCredential.user
                    console.log(user)
                    router.push({ name: 'menu' })
                })
                .catch((error) => {
                    const errorCode = error.code
                    console.log(errorCode)
                    this.errorMessage = error.message
                    alert(this.errorMessage)
                })
        },
        async signout() {
            await signOut(auth)
                .then(() => {
                    router.push({ name: 'login' })
                })
                .catch((error) => {
                    const errorCode = error.code
                    console.log(errorCode)
                    this.errorMessage = error.message
                    alert(this.errorMessage)
                })
        }
    }
})

用户提到将const auth = useFirebaseAuth()移至State中可正常运行,但不确定是否为正确实现方式。


正确实现方案

核心原因

useFirebaseAuth()依赖Vue的依赖注入系统,只能在组件的setup()函数、Pinia的setup()风格Store,或是Store的action内部调用,不能在Store外部的顶级作用域执行。

方案1:在每个Action内部获取Auth实例

将useFirebaseAuth()移至每个action内部,确保每次调用action时都能正确获取注入的Auth实例:

import { defineStore } from 'pinia'
import router from '../router/index'
import { useFirebaseAuth } from 'vuefire'
import { signOut, createUserWithEmailAndPassword, signInWithEmailAndPassword } from 'firebase/auth'

export const useUserStore = defineStore('UserStore', {
    state: () => {
        return {
            user: {},
            isLoggedIn: false,
            email: '',
            password: '',
            repassword: '',
            errorMessage: '',
        }
    },
    actions: {
        async register() {
            const auth = useFirebaseAuth()
            if (this.password === this.repassword) {
                try {
                    const userCredential = await createUserWithEmailAndPassword(auth, this.email, this.password)
                    const user = userCredential.user
                    console.log(user)
                    router.push('/:placeName')
                } catch (error) {
                    console.log(error.code)
                    this.errorMessage = error.message
                    alert(this.errorMessage)
                }
            } else {
                alert('Passwords must match')
            }
        },
        async login() {
            const auth = useFirebaseAuth()
            try {
                const userCredential = await signInWithEmailAndPassword(auth, this.email, this.password)
                const user = userCredential.user
                console.log(user)
                router.push({ name: 'menu' })
            } catch (error) {
                console.log(error.code)
                this.errorMessage = error.message
                alert(this.errorMessage)
            }
        },
        async signout() {
            const auth = useFirebaseAuth()
            try {
                await signOut(auth)
                router.push({ name: 'login' })
            } catch (error) {
                console.log(error.code)
                this.errorMessage = error.message
                alert(this.errorMessage)
            }
        }
    }
})

方案2:使用Pinia的Setup风格Store

改用Pinia的setup写法,在setup函数内部获取Auth实例,所有action可复用该实例,代码更简洁:

import { defineStore } from 'pinia'
import { ref } from 'vue'
import router from '../router/index'
import { useFirebaseAuth } from 'vuefire'
import { signOut, createUserWithEmailAndPassword, signInWithEmailAndPassword } from 'firebase/auth'

export const useUserStore = defineStore('UserStore', () => {
    const auth = useFirebaseAuth()
    const user = ref({})
    const isLoggedIn = ref(false)
    const email = ref('')
    const password = ref('')
    const repassword = ref('')
    const errorMessage = ref('')

    const register = async () => {
        if (password.value === repassword.value) {
            try {
                const userCredential = await createUserWithEmailAndPassword(auth, email.value, password.value)
                user.value = userCredential.user
                console.log(user.value)
                router.push('/:placeName')
            } catch (error) {
                console.log(error.code)
                errorMessage.value = error.message
                alert(errorMessage.value)
            }
        } else {
            alert('Passwords must match')
        }
    }

    const login = async () => {
        try {
            const userCredential = await signInWithEmailAndPassword(auth, email.value, password.value)
            user.value = userCredential.user
            console.log(user.value)
            router.push({ name: 'menu' })
        } catch (error) {
            console.log(error.code)
            errorMessage.value = error.message
            alert(errorMessage.value)
        }
    }

    const signout = async () => {
        try {
            await signOut(auth)
            router.push({ name: 'login' })
        } catch (error) {
            console.log(error.code)
            errorMessage.value = error.message
            alert(errorMessage.value)
        }
    }

    return {
        user,
        isLoggedIn,
        email,
        password,
        repassword,
        errorMessage,
        register,
        login,
        signout
    }
})

关于将Auth放入State的疑问

把useFirebaseAuth()放到state里虽能运行,但不推荐:

  • State应存储可序列化的应用状态数据,Auth实例是Firebase的工具对象,不属于状态范畴
  • 这种写法依赖Pinia初始化的时机,存在注入失败的潜在风险,不符合Vue依赖注入的规范

内容的提问来源于stack exchange,提问作者Obed Monsalve

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:45:10