팔로우/언팔로우 - 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: "언팔로우 성공" });
});
});