ChatGPTを使用したアプリ開発記【フォロー・フォロワー機能の改修】

## フォロー機能のコード

```src/FollowButton.js
import React, { useState, useEffect } from 'react';
	
    //	Firebase Firestore関連の関数をインポートしています。
	//	collection：コレクションを指定
	//	query, where：条件付きでデータ取得
	//	getDocs：クエリに一致するドキュメントを取得
	//	addDoc：新しいドキュメントを追加
	//	deleteDoc：ドキュメントを削除
	//	doc：特定のドキュメント参照を取得
import {
  collection,
  query,
  where,
  getDocs,
  addDoc,
  deleteDoc,
  doc
} from 'firebase/firestore';

import { db } from './FireBase';

// 親コンポーネントから currentUserId（自分）と targetUserId（相手）を受け取ります。
const FollowButton = ({ currentUserId, targetUserId }) => {
  
  // 現在フォロー中かどうかの状態を管理します。
  const [isFollowing, setIsFollowing] = useState(false);
  // フォロー関係を表すFirestoreのドキュメントIDを保持します（削除時に使います）。
  const [followDocId, setFollowDocId] = useState(null);
  // Firestore操作中のローディング状態を管理します。
  const [loading, setLoading] = useState(true);

// 初回レンダリング時、または currentUserId・targetUserId が変更されたときに実行。
  useEffect(() => {
    
    // フォロー状態をFirestoreから確認する関数。
    const checkFollow = async () => {

    // followers コレクションから、現在のユーザーが指定ユーザーをフォローしているかどうかを検索。
      const q = query(
        collection(db, 'followers'),
        where('follower_id', '==', currentUserId),
        where('followed_id', '==', targetUserId)
      );

      // 上記のクエリに一致するドキュメントを取得。
      const snapshot = await getDocs(q);

       // 該当ドキュメントが存在する＝フォロー中と判断して状態を更新。
      if (!snapshot.empty) {
        setIsFollowing(true);
        setFollowDocId(snapshot.docs[0].id);
      } else {
        setIsFollowing(false);
        setFollowDocId(null);
      }

     //	チェック完了後、ローディングを終了。
      setLoading(false);
    };

	//	自分自身はフォローしないため、その場合はチェックをスキップしてすぐローディング終了。	
    if (currentUserId && targetUserId && currentUserId !== targetUserId) {
      checkFollow();
    } else {
      setLoading(false);
    }

 //	currentUserId または targetUserId が変化したとき再実行。
  }, [currentUserId, targetUserId]);

// ボタンが押されたときにフォロー状態をトグル（切り替える）し、ローディング開始。
  const toggleFollow = async () => {
    setLoading(true);

   // フォロー中の場合は、該当ドキュメントを削除してフォロー解除。
    if (isFollowing && followDocId) {
      await deleteDoc(doc(db, 'followers', followDocId));
      setIsFollowing(false);
      setFollowDocId(null);

    //	フォローしていなければ、新しいフォローデータを追加。
    } else {
      const docRef = await addDoc(collection(db, 'followers'), {
        follower_id: currentUserId,
        followed_id: targetUserId,
      });
      setIsFollowing(true);
      setFollowDocId(docRef.id);
    }

    //	操作完了後にローディング終了。
    setLoading(false);
  };

// 	ローディング中 or 自分自身のプロフィールではボタンを非表示。
  if (loading || currentUserId === targetUserId) return null;




export default FollowButton;
```
## UIのコード
```Profile.js

import FollowButton from './FollowButton';
  return (
    <button
      onClick={toggleFollow}
      style={{
        backgroundColor: isFollowing ? '#ccc' : '#007bff',
        color: 'white',
        padding: '0.5rem 1rem',
        border: 'none',
        borderRadius: '8px',
        cursor: 'pointer',
        marginLeft: '1rem',
      }}
    >
      {isFollowing ? 'フォロー中' : 'フォロー'}
    </button>
  );
};


      {/* currentUserId と userId が異なる場合にフォローボタンを表示 */}
      {currentUserId && currentUserId !== uid && (
        <FollowButton currentUserId={currentUserId} targetUserId={uid} />
      )}
```

## UI

![スクリーンショット 2025-05-14 5.56.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1058366/bc832574-e042-4302-84cf-1550c51c85f9.png)