UfUzR64rRzYa_Question
@UfUzR64rRzYa_Question

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

firestoreの読み取り回数を削減したい

解決したいこと

タイトル通りfirestoreの読み取り回数を削減したいです

発生している問題・エラー

作業し始めて2時間ほどで読み取り回数が4万になっていることに気づきました。
スクリーンショット 2023-09-18 23.59.56.png

該当するソースコード

触っていたのは1ファイルのみなので以下のソースの中に問題があると思います。
特にTodoリスト、コメント表示の処理だろうとは思うのですが
どのようにアプローチしたらいいかがわからず解決する前に無料枠を超えてしまいました。

// import 略

const Show = () => {
// id
  const pathname = usePathname();
  const segments = pathname.split("/");
  const id = segments[segments.length - 1];
  // State
  const [todos, setTodos] = useState([]);
  const [comments, setComments] = useState([]);
  const { isOpen, onOpen, onClose } = useDisclosure();

  // Todoリスト
  const postsCol = collection(db, "posts");
  const queryRef = query(postsCol, where("Id", "==", id));
  (async () => {
    try {
      const querySnapshot = await getDocs(queryRef);
      const todoDocObj = querySnapshot.docs[0];
      if (todoDocObj) {
        const data = todoDocObj.data();
        const formattedCreate = format(data.Create.toDate(), "yyyy-MM-dd HH:mm");
        const formattedUpdate = format(data.Update.toDate(), "yyyy-MM-dd HH:mm");
        setTodos({
          Create: formattedCreate,
          Detail: data.Detail,
          Task: data.Task,
          Update: formattedUpdate,
        });
      }
    } catch (error) {
      // console.log(error);
    }
  })();

  // コメント表示
  const fetchComment = async () => {
    try {
      const cmtCol = collection(db, "comments");
      const cmtQueryRef = query(cmtCol, where("Id", "==", id), orderBy("commentCreate", "desc"));
      getDocs(cmtQueryRef).then((cmtSnapShot) => {
        const cmtObj = cmtSnapShot.docs.map((doc) => {
          return {
            commentName: doc.data().commentName,
            commentDetail: doc.data().commentDetail,
            commentCreate: format(doc.data().commentCreate.toDate(), "yyyy-MM-dd HH:mm"),
          };
        });
        setComments(cmtObj);
      });
    } catch (error) {
      console.log(error);
    }
  };
  useEffect(() => {
    fetchComment();
  }, []);

  // コメント追加
  const addComment = async (e) => {
    e.preventDefault();
    try {
      const { commentName, commentDetail } = e.target.elements;
      const newComment = doc(collection(db, "comments"));
      const comdetail = commentDetail.value;
      const comname = commentName.value;
      await setDoc(newComment, {
        Id: id,
        commentCreate: Timestamp.now(),
        commentDetail: comdetail,
        commentId: newComment.id,
        commentName: comname,
      });
      e.target.reset();
      onClose();
      fetchComment();
    } catch (error) {
      // console.log(error);
    }
  };

return(<></>)
}

実装中の機能

1todo読み込み ページidと紐づいたtodoデータを表示する(Todoリスト)
2コメント読み込み ページidと紐づいたコメントデータを表示する(コメント表示)
3モーダル表示
4コメント投稿(コメント追加)

自分で試したこと

1リロードでどれくらいアクセスがあるか3回ほどテストできましたが、
1リロード1000以上カウントされていました。

補足

コレクションは2つ、登録されているドキュメント数も5件以下なのでデータが多いということはない認識です。

1

1Answer

レンダリングのたびにstateを更新しているため、多くの回数APIを実行しているのだと思われます。

Reactは基本的に以下のタイミングで再レンダリングされます。

以下のコードが実行されると、stateを更新しているので再レンダリングが発生し、さらにstateが更新されていくので無限ループが発生してしまいます。

 (async () => {
    try {
      const querySnapshot = await getDocs(queryRef);
      const todoDocObj = querySnapshot.docs[0];
      if (todoDocObj) {
        const data = todoDocObj.data();
        const formattedCreate = format(data.Create.toDate(), "yyyy-MM-dd HH:mm");
        const formattedUpdate = format(data.Update.toDate(), "yyyy-MM-dd HH:mm");
        setTodos({
          Create: formattedCreate,
          Detail: data.Detail,
          Task: data.Task,
          Update: formattedUpdate,
        });
      }
    } catch (error) {
      // console.log(error);
    }
  })();

対策としては、useEffectを使って依存配列が変わらなければAPIを呼ばないようにすると解決できると思われます。

1Like

Comments

  1. ご回答ありがとうございます!
    無料枠の制限がリセットされconsole.logを挟んで実行したところ無限レンダリングが発生していることを確認でき、useEffectを使用しての修正も対応できました。
    サンプルコードまで添付いただき恐れ入ります。
    まったく初歩的な内容で申し訳ありません:sob:

Your answer might help someone💌