【Next.js+Firebase】
自身の勉強過程を
無理やり作品にしていく
Vol.4:Cloud Firestore編

  • 【Next.js+Firebase】
    自身の勉強過程を無理やり作品にしていくVol.4:Cloud Firestore編

    Firebase

    どうも!こんにちは!

    Next.js + Firebaseで勉強した内容をアウトプットする連載です。
    今回はCloud Firestoreというデータベースを使用した、Todoリストを作成していきたいと思います。

    完成したアプリは自己紹介ページの「ギャラリー」に掲載しているので、よかったら見てみてください!

    それではスタートです!

    作成したTodoリスト

    Todoリスト画面

    よくあるTodoリストではありますが、「タスク追加」にタスク名を入れて、「タスクを追加する」ボタンをクリックすると下側にタスクが追加されます。

    また下側に追加されたタスク名編集やタスク削除で、更新・削除が行えます。

    これをCloud Firestoreで実装しましたので解説をしていきます。

    また私事ですが、
    いきなり書き込みを行う前に、Firebase管理画面からCloud Firestoreへダミーデータなどを入れて、まずは読み込みができるかを実施したほうが分かりやすい・実装しやすいと思いますので、今回は読み込み→書き込みの順番で書いていきます。

    Cloud Firestore実装

    実装するにあたりまずは、Cloud Firestoreのドキュメントを確認しましょう。

    Cloud Firestoreのインスタンスを初期化しないと使えないらしいですが、これは以前の記事で準備しているのでそれを使っていきます。

    コード

    以下のように記述することで、Cloud Firestoreからデータを読み込み表示することができると思います。

    // pages/firestore/index.tsx
    
    import { useState, useEffect } from 'react';
    import type { NextPage } from 'next';
    import { LoadingFirebase } from '@/components/Loading/LoadingFirebase';
    import { db } from '../../../firebase';
    
    type TASKSTATE = {
      id: string;
      title: string;
    }[];
    
    const Index: NextPage = () => {
      const [tasks, setTasks] = useState<TASKSTATE>([{ id: '', title: '' }]);
      const [isFetch, setIsFetch] = useState<Boolean>(false);
    
      // Firestoreのデータを取得;
      useEffect(() => {
        const unSub = db.collection('tasks').onSnapshot((snapshot) => {
          setTasks(
            snapshot.docs.map((doc) => ({ id: doc.id, title: doc.data().title }))
          );
          setIsFetch(true);
        });
        return () => unSub();
      }, []);
    
      if (!isFetch) {
        return <LoadingFirebase />;
      }
    
      return (
        <>
          <h2>タスク読み込み</h2>
          <ul>
            {tasks.map((task, index) => {
              return (
                <li key={task.id}>{task.title}</li>
              );
            })}
          </ul>
        </>
      );
    };
    
    export default Index;

    データの読み込みから表示までに、必要なことは以下です。

    1. ページアクセス時Cloud Firestoreのデータを読み込む
    2. Cloud Firestoreのデータ読み込みが完了するまでローディング画面を表示

    一つづつ見ていきましょう。

    ページアクセス時Cloud Firestoreのデータを読み込む

    ページヘのアクセス時なので、React HooksのuseEffectを使用します。

    useEffectはVueでいうmountedだと思ってもらえればよいです。
    以下の記述が該当箇所です。

     // Firestoreのデータを取得;
     useEffect(() => {
      const unSub = db.collection('tasks').onSnapshot((snapshot) => {
       setTasks(
        snapshot.docs.map((doc) => ({ id: doc.id, title: doc.data().title }))
       );
       setIsFetch(true);
      });
      return () => unSub();
     }, []);


    また読み込んだデータを管理するため、React HooksのuseStateを使用します。

     const [tasks, setTasks] = useState<TASKSTATE>([{ id: '', title: '' }]);


    Cloud Firestoreのデータは、以下記述の引数snapshotに入ってきます。

    db.collection('tasks').onSnapshot((snapshot) => {});


    snapshotにあるデータをmapで回して、useStateのtasksにセットします。

      const unSub = db.collection('tasks').onSnapshot((snapshot) => {
       setTasks(
        snapshot.docs.map((doc) => ({ id: doc.id, title: doc.data().title }))
       );


    こうすることで、ページアクセス時にCloud Firestoreのデータがtasksに格納されますので、そのtasksを繰り返して表示させればOKです。

     return (
      <>
       <h2>タスク読み込み</h2>
       <ul>
        {tasks.map((task, index) => {
         return (
          <li key={task.id}>{task.title}</li>
         );
        })}
       </ul>
      </>
     );

    Cloud Firestoreのデータ読み込みが完了するまでローディング画面を表示

    現状Cloud Firestoreからデータを読み込んで表示することはできましたが、ページアクセス時は何も画面に表示されていなく、データ読み込みが完了したら表示されるような挙動になるかと思います。

    そのため、データ読み込みが完了するまでローディングを表示させ、読み込みが完了したら読み込んだデータを表示するという形に変更したいと思います。

    データの管理で使用したuseStateをもう一つ用意します。

    今回はデータの読み込みが完了したらということなので、isFetchとし初期値はfalseとします。

     const [isFetch, setIsFetch] = useState<Boolean>(false);


    次にuseEffectでCloud Firestoreから読み込みが完了したら、isFetchをtrueにしたいので以下のようにします。

     useEffect(() => {
     const unSub = db.collection('tasks').onSnapshot((snapshot) => {
      setTasks(
      snapshot.docs.map((doc) => ({ id: doc.id, title: doc.data().title }))
      );
      setIsFetch(true); // ここでisFetchをセット
     });


    そして読み込んだデータを表示するJSXの前に、isFetchで判定を行い、ローディングの表示・非表示を行います。
    ※私の場合はローディング系をコンポーネント化しているので、そのコンポーネントを表示させてます。

     // isFetchがfalseだったらローディングを表示、trueだったら読み込んだデータを表示
     if (!isFetch) {
      return <LoadingFirebase />;
     }
    
     return (
      <>
       <h2>タスク読み込み</h2>
       <ul>
        {tasks.map((task, index) => {
         return (
          <li key={task.id}>{task.title}</li>
         );
        })}
       </ul>
      </>
     );


    これで、読み込みが完了するまではローディングが表示され、読み込みが完了したらデータが表示されるかと思います。

    次回

    今回は読み込みだけでしたので、次回は書き込みについてをやっていきたいと思います。

    それでは次回もよろしく〜

記事をシェアする