firestoreでのデータの扱い

## データの取得

### リアルタイム更新のデータの取得(querySnapshot)

https://firebase.google.com/docs/firestore/query-data/listen?hl=ja#listen_to_multiple_documents_in_a_collection

#### custom hookで取得しやすくする

```hook/useCollection.tsx

import { useEffect, useState } from "react";
import { db } from "../../firebase";
import { QueryDocumentSnapshot } from "firebase/firestore/lite";
import { onSnapshot, collection, DocumentData, CollectionReference } from "firebase/firestore";

interface Channels {
  id: string;
  channel: QueryDocumentSnapshot<DocumentData>;
}

const useCollection = (data: string) => {
  const [documents, setDocuments] = useState<Channels[]>([]);

  useEffect(() => {
    let collectionRef: CollectionReference<DocumentData> = collection(db, data);
    onSnapshot(collectionRef, (snapshot) => {
      let results: Channels[] = [];
      snapshot.docs.forEach((doc) => {
        results.push({ id: doc.id, channel: doc.data() as any });
      });
      setDocuments(results);
    });
  }, [data]);

  return { documents };
};

export default useCollection;

```

使いたい箇所

```Sidebar.jsx
import React from "react";
import useCollection from "../hook/useCollection.tsx";

const Sidebar = () => {
  const currentUser = useAppSelector((state) => state.currentUser);

  const { documents: channels } = useCollection("channels");
  return (
    <div className="sidebar">
      
    </div>
  );
};

export default Sidebar;


```

## データの作成

### データの作成(collection)

https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja#add_a_document

```Sidebar.tsx
import { collection, addDoc } from "firebase/firestore";
import React from "react";
import { auth, db } from "../../firebase.ts";

const Sidebar = () => {
  const { documents: channels } = useCollection("channels");
  const addChannel = async () => {
    const channelName: string | null = prompt("新しいチャンネルを作成します");

    if (channelName) {
      await addDoc(collection(db, "channels"), {
        channelName: channelName,
      });
    }
  };
  return (
    <div className="sidebar">
    </div>
  );
};

export default Sidebar;

```

```src/app/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

```

### データの作成(subCollection)

```chat.tsx
import {
  addDoc,
  collection,
  CollectionReference,
  DocumentData,
  onSnapshot,
  serverTimestamp,
  Timestamp,
} from "firebase/firestore";
import React, { useEffect, useState } from "react";
import { useAppSelector } from "../../app/hooks.ts";
import { db } from "../../firebase.ts";

interface Messages {
  timestamp: Timestamp;
  message: string;
  user: {
    uid: string;
    photo: string;
    email: string;
    displayName: string;
  };
}

const Chat = () => {
  const [messages, setMessages] = useState<Messages[]>([]);
  const channelName = useAppSelector((state) => state.channel.channelName);
  const channelId = useAppSelector((state) => state.channel.channelId);
  const currentUser = useAppSelector((state) => state.currentUser.currentUser);

  const sendMessage = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    e.preventDefault();

    const collectionRef: CollectionReference<DocumentData, DocumentData> = collection(
      db,
      "channels",
      String(channelId),
      "messages",
    );
    await addDoc(collectionRef, {
      message: inputText,
      timestamp: serverTimestamp(),
      user: currentUser,
    });
  };

  return (
    <div className="chat">
    </div>
  );
};

export default Chat;

```

```src/app/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

```