Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@HIL_FIGER_sg

vuexfireでbindFirestoreRefすると、idのenumerable属性がfalseになる問題

More than 1 year has passed since last update.

備忘録を兼ねて

問題点

Vuexfireのドキュメンテーションに以下の記述があります。

Any document bound by Vuexfire will retain it's id in the database as a non-enumerable, read-only property.

bindしたデータをそのままviewから呼び出すのであれば、enumerable属性の真偽に関わらずdata.idでidプロパティにアクセスできるので問題が生じません。しかし、Object.entries等にObjectを渡した際は検出してくれません。

vuex.js
const db = firebaseApp.firestore();

state = { data: null } // -> { value: 'hoge', id: 'fuga' }
// idはenumerable: falseとして保存されている

actions = {
  bindData: firestoreAction(async ({ bindFirestoreRef }) => {
    return bindFirestoreRef('data', db.collection('hoge'));
  }),
}
index.js

for (let [key, value] of Object.entries(this.$store.state.data)) {
  console.log(`${key}: ${value}`); // -> { value: 'hoge' }
}

この仕様は、例えばObjectをcomposition-API等に通した際などに問題となり得ます。

main.vue

setup(props, context) {
  const data = ref(context.root.$store.state.data);
  console.log(data.value) // -> { value: 'hoge' }
}

解決法

さて、VuexfireのAPIReferenceに次の記述があります

options can contain
serialize: a function to provide a custom serialization strategy when a document from firebase is set on the Vue instance. This allows to customize the id key, to transform data, etc.

さらにVuefireのReferenceを辿ると次のように記述されています

options.serialize: The function receives a DocumentSnapshot
as its first argument and is expected to return a plain object to be set on the Vue Instance. Here is the default function that is used when no override is provided:

これに従ってserialize関数を定義し、callbackとしてbindFirestoreRefに渡すとenumerable属性がtrueになってくれます。

vuex.js
const serialize = (snapshot: firestore.DocumentSnapshot) => {
  return Object.defineProperty(snapshot.data(), 'id', {
    value: snapshot.id,
    enumerable: true,
  });
};
actions = {
  bindData: firestoreAction(async ({ bindFirestoreRef }) => {
    return bindFirestoreRef('data', db.collection('hoge'), { serialize });
  })
}
main.vue

setup(props, context) {
  const data = ref(context.root.$store.state.data);
  console.log(data.value) // -> { value: 'hoge', id: 'fuga' }
}

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?