1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-05-23

備忘録を兼ねて

問題点

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' }
}

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?