google-cloud-firestorevuejs3piniavuefire

How to properly render firestore retrieved data stored inside pinia?


I have two variables in my userStore.js, userData which is populated by the object returned by the login function and profileData which I populate with data from firestore using a VueFire composable inside the getUserData function. VueDevTools shows that both variables are populated correctly with all the expected values.

capture of vueDevTools showing that the data was stored correctly

The problem is that in my template I can render data from the userData variable but can't render data from the profileData variable but I can't understand why.

The console show no errors but it throws me this warning about the profileData.value declaration line: [Vue warn]: inject() can only be used inside setup() or functional components.

This is my userStore.js

export const useUserStore = defineStore("UserStore", () => {
  ...
  const userData = ref({});
  const profileData = ref({});

  async function login() {
    await signInWithEmailAndPassword(auth, this.email, this.password)
      .then((userCredential) => {
        userData.value = userCredential.user;
        getUserData(userCredential.user.uid);
      })
      .catch((error) => {
        const errorCode = error.code;
        console.log(errorCode);
        errorMessage.value = error.message;
        alert(errorMessage.value);
      });
  }

  async function getUserData(uid) {
    profileData.value = useDocument(doc(collection(db, "users"), uid), {
      once: true,
    });
  }

  return {
    userData,
    profileData,
    login
  };
});

This is my SFC

<template>
  <aside
    <div>
      <div><p>{{userData.profileData.fullName}}</p></div> <-- This line shows nothing
      <div><p>{{userData.userData.email}}</p></div> <-- This line renders correctly
    </div>
  </aside>
</template>

<script setup>
import { ref } from "vue";
import { useUserStore } from "../stores/userStore.js";
const userData = useUserStore();
</script>

Solution

  • Your userStore.js seems correct, but make sure that profileData is initialized as null or an empty object, and you're updating it properly when the document is retrieved from Firestore.

    export const useUserStore = defineStore("UserStore", () => {
      const userData = ref(null);
      const profileData = ref(null); // initialized as null to handle loading state
    

    Also, add optional chaining (?.) to ensure that if profileData is not yet populated, it won't throw an error. This should render correctly now.

    <template>
      <aside>
        <div>
          <div><p>{{ profileData.value?.fullName }}</p></div>
          <div><p>{{ userData.userData.email }}</p></div>
        </div>
      </aside>
    </template>
    </body></html>
    

    The reason why you are not seeing any error in console is because you have defined profile data as an object, and when we try to access any non existing property of object, we don't get an error but get undefined. See below code for your understanding.

    const obj = {
      name: 'Test'
    }
    console.log(obj.name) // This will print 'Test'
    console.log(obj.something) // This will print undefined because something is not present
    console.log(obj.something.try) // This will give error, because we are trying to access try property of something, where something is undefined and we cannot access propety of undefined