学ぶ
これを読めばFirestoreでのリレーションもどきについてはおおむね理解できるが、RDBが恋しくてたまらない。
出来上がったカスタムhook
いいね状態を判定するためのRefを監視して、トグルするようにしている。
incrementメソッドを使用する場合、データを監視しているSubscribeが保留中の書き込みを反映しない設定にしている(snapshot.metadata.hasPendingWritesを弾いたり)と何故か更新を受け取れないようで、この設定を切る必要があった。なぜかはよくわからない。
また、拡張機能の分散カウンタも試してみたが、batch処理に絡められないのと、エミュレーター上で動かすと権限エラーで使用できず苦しんだ。
かなりの数のリクエストを送ってみてもincrementで処理できていたためコストにリターンが見合っていないと考え、今回は使用しなかった。
likePost.ts
import { useFirestoreWriteBatch } from '@react-query-firebase/firestore';
import { doc, increment, writeBatch } from 'firebase/firestore';
import { db } from '@/config/firebase';
import { useFirestore } from '@/hooks/useFirestore';
import { useAuthContext } from '@/lib/auth';
import { timestampTemp } from '@/utils/constants';
import type { Post } from '../types';
export type LikePostDTO = {
data: Post;
};
type UseLikePostOptions = LikePostDTO & {
config?: {
// ...
};
};
export const useLikePost = ({ data }: UseLikePostOptions) => {
const auth = useAuthContext();
const batch = writeBatch(db);
const LikePostBatch = useFirestoreWriteBatch(batch);
const postRef = doc(db, 'users', data.author.path.split('/')[1], 'posts', data.id);
const userRef = doc(db, 'users', auth?.user ? auth?.user?.uid : '_');
const likedUserRef = doc(postRef, 'likedUsers', auth?.user ? auth?.user?.uid : '_');
const likedPostRef = doc(userRef, 'likedPosts', data.id);
const likedUserDoc = useFirestore<Post>(likedUserRef);
const isLiked = !!likedUserDoc.data && !likedUserDoc.isLoading; // 読み込み済みでデータがあればいいね済み
const canMutate = !likedUserDoc.isLoading; // 読み込み中はいいねできない
const mutateToggle = () => {
if (canMutate) {
isLiked ? mutateUnLikeBatch() : mutateLikeBatch();
}
};
const mutateLikeBatch = () => {
// いいねをつけたユーザーのリストに自分を追加
batch.set(likedUserRef, { ...timestampTemp });
// 自分のいいねした投稿リストに追加
batch.set(likedPostRef, {
originRef: postRef,
...timestampTemp,
});
batch.update(postRef, { likeCount: increment(1) });
LikePostBatch.mutate();
};
const mutateUnLikeBatch = () => {
// いいねをつけたユーザーのリストから自分を削除
batch.delete(likedUserRef);
// 自分のいいねした投稿リストから削除
batch.delete(likedPostRef);
batch.update(postRef, { likeCount: increment(-1) });
LikePostBatch.mutate();
};
return {
...LikePostBatch,
mutateToggle,
isLiked,
canMutate,
};
};