팔로우/언팔로우 - Part1 팔로우/언팔로우 하기

Project Diary/React + MariaDB (PicShare WebApp)

사용자가 다른 사용자를 팔로우하거나 언팔로우할 수 있는 기능을 구현합니다. 이 기능은 팔로우 버튼을 통해 사용자 목록 페이지와 개인 피드 페이지에서 제공되며, 프론트엔드와 백엔드가 상호작용하여 팔로우/언팔로우 상태를 업데이트합니다. 데이터베이스에 팔로우 관계를 저장하고 삭제하는 과정을 포함합니다.


 

데이터베이스 구조 설정

 

    • followerId : users 테이블의 userNo팔로우하는 유저
    • followeeId : users 테이블의 userNo 에게 팔로우된 유저

프론트엔드

 

1. 팔로우 버튼 컴포넌트 (FollowButton.jsx)

 

1-1 팔로우 버튼 컴포넌트

> 상태 및 기본 설정

const FollowButton = ({ userNo }) => {
  const dispatch = useDispatch();
  const currentUser = useSelector((state) => state.members.user);
  const followingList = useSelector((state) => state.follows.followingList);
  const [isFollowing, setIsFollowing] = useState(false);

  // useEffect: 현재 사용자가 팔로우하고 있는지 확인하여 isFollowing 상태를 설정합니다.
  // 이를 통해 팔로우/언팔로우 버튼이 동기화됩니다.
  useEffect(() => {
    if (followingList && followingList.length > 0) {
      setIsFollowing(
        followingList.some((followee) => followee.userNo === userNo)
      );
    }
  }, [followingList, userNo]);
  • useEffect : 현재 사용자가 팔로우하고 있는지 확인하여 isFollowing 상태를 설정합니다. 이를 통해 팔로우/언팔로우 버튼이 동기화됩니다.
  • setIsFollowing : 팔로우 목록에 따라 현재 사용자가 해당 사용자를 팔로우하고 있는지 여부를 설정합니다.

> 팔로우 처리 함수

  // 팔로우 처리 함수
  const handleFollow = async () => {
    try {
      await axios.post(`${serverUrl}/follow/followfunction`, {
        followerId: currentUser.userNo,
        followeeId: userNo,
      });
      dispatch(fetchFollowingList(currentUser.userNo)); // 팔로잉 목록 업데이트
      dispatch(fetchFollowerList(currentUser.userNo)); // 팔로워 목록 업데이트
    } catch (error) {
      console.error("Error following user:", error);
    }
  };
  • handleFollow : 팔로우 요청을 서버에 보내고, 팔로잉 및 팔로워 목록을 업데이트합니다.
    - axios.post : 서버에 팔로우 요청을 보냅니다.
    - dispatch(fetchFollowingList(currentUser.userNo)) : 팔로잉 목록을 업데이트합니다.
    - dispatch(fetchFollowerList(currentUser.userNo)) : 팔로워 목록을 업데이트합니다.

>  언팔로우 처리 함수

  // 언팔로우 처리 함수
  const handleUnfollow = async () => {
    try {
      await axios.post(`${serverUrl}/follow/unfollowfunction`, {
        followerId: currentUser.userNo,
        followeeId: userNo,
      });
      dispatch(fetchFollowingList(currentUser.userNo)); // 팔로잉 목록 업데이트
      dispatch(fetchFollowerList(currentUser.userNo)); // 팔로워 목록 업데이트
    } catch (error) {
      console.error("Error unfollowing user:", error);
    }
  };
  • handleUnfollow: 언팔로우 요청을 서버에 보내고, 팔로잉 및 팔로워 목록을 업데이트합니다.
    - axios.post : 서버에 언팔로우 요청을 보냅니다.
    - dispatch(fetchFollowingList(currentUser.userNo)) : 팔로잉 목록을 업데이트합니다.
    - dispatch(fetchFollowerList(currentUser.userNo)) : 팔로워 목록을 업데이트합니다.

> 버튼 렌더링

  return (
    <FollowButtonBlock>
      <button onClick={isFollowing ? handleUnfollow : handleFollow}>
        {isFollowing ? "Unfollow" : "Follow"}
      </button>
    </FollowButtonBlock>
  );
};

export default FollowButton;

 

 

2. 프로필 섹션 컴포넌트 (ProfileSection.jsx)

이 컴포넌트는 사용자 개인 피드 페이지에서 팔로우 버튼을 렌더링합니다.

팔로우 버튼은 currentUserNo와 targetUserNo가 다를 경우에만 표시됩니다.
- currentUserNo : 현재 로그인된 유저
- targetUserNo : 개인 페이지의 fetch된 유저

 

2-1 프로필 섹션 컴포넌트

> 상태 및 기본 설정

const ProfileSection = ({ length }) => {
  const navigate = useNavigate();
  const dispatch = useDispatch();
  const { userNo } = useParams(); // URL에서 유저 번호 추출
  const targetUserNo = parseInt(userNo); // URL에서 받아온 유저 번호
  const currentUser = useSelector((state) => state.members.user);
  const currentUserNo = currentUser.userNo;

  const [user, setUser] = useState();
  const [loading, setLoading] = useState(true);

 

>  사용자 정보 로드

  useEffect(() => {
    const fetchTargetUserData = (targetUserNo) => {
      axios
        .get(`${serverUrl}/auth/users?targetUserNo=${targetUserNo}`)
        .then((res) => {
          const data = res.data;
          setUser(data);
          setLoading(false);
        })
        .catch((err) => console.log(err));
    };

    fetchTargetUserData(targetUserNo);
    dispatch(fetchFollowerList(targetUserNo));
    dispatch(fetchFollowingList(targetUserNo));
  }, [userNo, targetUserNo, dispatch]);
  • fetchTargetUserData: 서버에서 타겟 사용자 정보를 가져옵니다.
    - axios.get : 서버에 사용자 정보 요청을 보냅니다.
    - setUser(data): 받아온 사용자 정보를 상태에 저장합니다.
    - setLoading(false): 로딩 상태를 해제합니다.
  • dispatch(fetchFollowerList(targetUserNo))
    - 타겟 사용자의 팔로워 목록을 가져옵니다.
  • dispatch(fetchFollowingList(targetUserNo))
    - 타겟 사용자의 팔로잉 목록을 가져옵니다.

> 프로필 섹션 렌더링

  if (loading)
    return (
      <div>
        로딩중
      </div>
    );

  return (
    <ProfileSectionBlock>
      <div className="profile">
        <img
          src={`${serverUrl}/uploads/${user[0].profilePicture}`}
          alt="프로필사진"
        />
        <div className="length">
          <p>{length}</p>
          <p>게시물</p>
        </div>
        <div className="length">
          <p>{user[0].followerCount || 0}</p>
          <p>팔로워</p>
        </div>
        <div className="length">
          <p>{user[0].followingCount || 0}</p>
          <p>팔로잉</p>
        </div>
      </div>
      <span className="nickname">{user[0].userNickname}</span>
      <span className="modify">
        {currentUserNo === targetUserNo && (
          <Link to="/profilemodify">
            <FaPen />
          </Link>
        )}
      </span>
      <div className="btn">
        {currentUserNo !== targetUserNo && (
          <FollowButton userNo={targetUserNo} />
        )}
      </div>
    </ProfileSectionBlock>
  );
};

export default ProfileSection;

 


 

백엔드

- followRouter.js

 

1. 팔로우 기능 엔드포인트

import express from "express";
import { db } from "../db.js";

const followRouter = express.Router();

// 팔로우 기능
followRouter.post("/followfunction", (req, res) => {
  const { followerId, followeeId } = req.body;
  const sql = "INSERT INTO follows (followerId, followeeId) VALUES (?, ?)";
  db.query(sql, [followerId, followeeId], (err, result) => {
    if (err) {
      console.error("팔로우 중 오류 발생:", err);
      return res.status(500).json({ message: "팔로우 실패" });
    }
    return res.status(200).json({ message: "팔로우 성공" });
  });
});

 

2. 언팔로우 기능 엔드포인트

// 언팔로우 기능
followRouter.post("/unfollowfunction", (req, res) => {
  const { followerId, followeeId } = req.body;
  const sql = "DELETE FROM follows WHERE followerId = ? AND followeeId = ?";
  db.query(sql, [followerId, followeeId], (err, result) => {
    if (err) {
      console.error("언팔로우 중 오류 발생:", err);
      return res.status(500).json({ message: "언팔로우 실패" });
    }
    return res.status(200).json({ message: "언팔로우 성공" });
  });
});