Skip to content

Instantly share code, notes, and snippets.

@TeXmeijin
Last active November 1, 2020 23:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TeXmeijin/380e52febdae921f31afe382af1bb40f to your computer and use it in GitHub Desktop.
Save TeXmeijin/380e52febdae921f31afe382af1bb40f to your computer and use it in GitHub Desktop.
vue-composition-apiでFirestoreからデータを読み取れるカスタムフックuseCollection.tsを作った【react-firebase-hooks風】
import firebase, { firestore } from 'firebase'
import {
computed,
onUnmounted,
reactive,
Ref,
toRefs,
watch,
} from '@vue/composition-api'
import QuerySnapshot = firebase.firestore.QuerySnapshot;
import FirestoreDataConverter = firebase.firestore.FirestoreDataConverter;
// 戻り値はジェネリクスで型を指定できる
export type CollectionData<T> = {
values: Ref<T[]>,
loading: Ref<boolean>,
error: Ref<Error | null>,
}
type useCollectionData = {
<T extends { id: string }> (
getQuery: () => firestore.Query,
option?: {
dataConverter?: FirestoreDataConverter<T>
}
): CollectionData<T>
}
export const useCollectionData: useCollectionData = <T extends { id: string }> (
getQuery,
option
) => {
const {
snapshot, loading, error,
} = useCollection<T>(getQuery, option)
const values = computed(
() => {
return (snapshot.value
? snapshot.value.docs.map(doc => {
return {id: doc.id, ...doc.data()}
})
: []) as T[]
}
)
return {
values, loading, error,
}
}
type SnapshotState = {
snapshot: undefined | QuerySnapshot,
loading: boolean,
error: Error | null
}
export const useCollection = <T> (
getQuery: () => firestore.Query,
option?: {
dataConverter?: FirestoreDataConverter<T>
}
) => {
const snapshotState = reactive<SnapshotState>({
snapshot: undefined,
loading: true,
error: null,
})
const query = computed(() => getQuery())
let listener = () => {
}
const bindSnapshotHandler = () => {
if (!query.value) return
listener()
snapshotState.loading = true
const builtQuery = option?.dataConverter ? query.value.withConverter(option.dataConverter) : query.value
listener = builtQuery.onSnapshot({
next: val => {
snapshotState.snapshot = val
snapshotState.loading = false
},
error: err => {
snapshotState.error = err
snapshotState.loading = false
},
})
}
// マウント完了時か、クエリが変化したときにデータを読み込む
watch(query, bindSnapshotHandler, {immediate: true})
onUnmounted(() => {
listener()
})
return {
...toRefs(snapshotState),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment