setIsPending(res.data.pendingGroups.includes(group => group._id === groupId) ? true : false);

신청중인 그룹에 해당 페이지의 그룹 id가 있는지 확인 → 있으면 신청중, 없으면 신청하기

이렇게 하려고 했는데 includes 메서드가 적절하지 않다는걸 알게됨

setIsPending(res.data.pendingGroups.some(group => group._id === groupId) ? true : false);

상세 그룹 페이지 그룹 리더 정보 id로 가져와서 게시글 작성자로 설정하는거 해야됨

그리고 그룹 id 로 조회해서 그룹 정보 업데이트하는거 해야됨

{Object.keys(top3).length > 0 && Object.keys(other).length > 0 ? (
        <>
          <UserRank userTop3={top3.userTop3} userOther={other.userOther} />
          <GroupRank groupTop3={top3.groupTop3} groupOther={other.groupOther} />
        </>
      ) : (
        '하이'
      )}

state 값이 제대로 업데이트 될 때 컴포넌트를 랜더링 하고싶었는데 계속 undefined 에러 뜸

이렇게 조건부 랜더링을 통해 해결

—> 이거보다 setState 콜백을 통해서 해결하는게 나을듯..

setState 콜백은 언제쓸까?

: react에서 setState의 Callback 함수를 사용하는 경우는 state를 변경 후 변경된 state를 사용하는 경우입니다.

이렇게 하니까 바로 해결된다 ㅜㅜㅜㅜ

import React, { useEffect, useState } from 'react';
import { API } from '../../utils/axios';
import { chatSocket } from '../../utils/socketServer';
import { useSelector } from 'react-redux';
import { useParams, useNavigate, useLocation } from 'react-router-dom';
import { IoMdArrowRoundBack } from 'react-icons/io';
import Button from '../../components/common/Button';
import { Badge } from 'flowbite-react';

export default function DetailGroupPage() {
  const { groupId } = useParams();
  // const location = useLocation();
  // console.log('@@@#$@#$#@$#@$@#$ location 새로고침>>>>', location);
  // const { groupInfo } = location.state;
  const [groupInfo, setGroupInfo] = useState({});
  const [isPending, setIsPending] = useState(null);
  const { id: userId, nickName: userName } = useSelector(state => state.user?.userInfo);
  const [leaderName, setLeaderName] = useState('');
  const [profileImgPath, setProfileImgPath] = useState('');
  // const { subject, imagePath, category, description, time, leader, maxMember } = groupInfo;
  // console.log('룸아이디 오는거 확인>>>', roomId);
  // console.log('그룹정보 오는거 확인>>>', groupInfo);

  // console.log('잘되나>>', subject, imagePath, category, description, time, leader, maxMember);

  const navigate = useNavigate();

  // 채팅창 이동
  const handleChat = () => {
    chatSocket.emit('login', userName, res => {
      if (res && res.isOk) {
        console.log('successfully login', res);
        navigate(`/group/chat/${groupId}`);
      } else {
        console.log('fail to login', res);
        alert('로그인해주세요!');
      }
    });
  };

  // 뒤로가기
  const handleGoBack = () => {
    navigate(-1);
  };

  // 그룹 삭제
  const deleteGroup = async () => {
    try {
      const res = await API.delete(`group/studyGroup/${groupId}/members`);
      // console.log(res.data.message);
      alert(`${res.data.message}`);
      navigate('/');
    } catch (error) {
      console.error('그룹 삭제에 실패하셨습니다. ->', error);
    }
  };

  //그룹 탈퇴
  const leaveGroup = async () => {
    try {
      const res = await API.delete(`group/studyGroup/${groupId}`);
      // console.log(res.data.msg);
      alert(`${res.data.msg}`);
      navigate('/');
    } catch (error) {
      console.error('그룹 탈퇴에 실패하셨습니다. ->', error);
    }
  };

  useEffect(() => {
    const getGroupInfo = async () => {
      try {
        const res = await API.get(`/group/find/${groupId}`);
        if (res.data.isSuccess) {
          setGroupInfo(prevGroupInfo => {
            const newGroupInfo = res.data.GroupInfo;
            if (Object.keys(newGroupInfo).length > 0) {
              (async () => {
                const leaderRes = await API.get(`/user/${newGroupInfo.group_leader}`);
                if (leaderRes.data.isSuccess) {
                  const leaderInfo = leaderRes.data.userInfo;
                  setLeaderName(leaderInfo.nick_name);
                  setProfileImgPath(leaderInfo.user_profile_image_path);
                }
              })();
            }
            return newGroupInfo;
          });
        }
      } catch (err) {
        console.error(err);
      }
    };
    getGroupInfo();
  }, [groupId]);

  useEffect(() => {
    const getPendingGroups = async () => {
      try {
        const res = await API.get('/group/pendingGroups');
        setIsPending(res.data.pendingGroups.some(group => group._id === groupId) ? true : false);
      } catch (error) {
        console.error('Error fetching pending groups:', error);
      }
    };
    getPendingGroups();
  }, [groupId, isPending]);

  const handleGroupRequest = async groupId => {
    try {
      const res = await API.post(`/group/studyGroup/${groupId}/join`);
      if (!res.data.isFull) {
        const data = res.data.message;
        setIsPending(true);
        alert(data);
      } else {
        alert(`${res.data.message}`);
      }
    } catch (err) {
      console.error(err.message);
      alert('요청 처리 중 오류가 발생했습니다.');
    }
  };

  const handleCancelRequest = async () => {
    try {
      const res = await API.delete(`/group/studyGroup/${groupId}/joinRequests`);
      if (res.data.isSuccess) {
        setIsPending(false);
        alert(`${res.data.message}`);
      }
    } catch (err) {
      console.error(err);
    }
  };

  const {
    _id,
    daily_goal_time,
    group_category,
    group_description,
    group_image_path,
    group_leader,
    group_maximum_member,
    group_name,
    members,
  } = groupInfo;

  return (
    <>
      {Object.keys(groupInfo).length === 0 && <div className="loading">로딩 중...</div>}
      {Object.keys(groupInfo).length > 0 && leaderName && profileImgPath && (
        <div className="studyContentWrap flex flex-col break-all">
          <section className="studyContent_postHeader mb-5">
            <div className="btnWrap flex justify-between items-center mb-5">
              <Button handleClick={handleGoBack} customStyle={'!bg-transparent !text-primary !text-3xl'}>
                {<IoMdArrowRoundBack />}
              </Button>
              {!members.includes(userId) ? (
                isPending ? (
                  <Button handleClick={handleCancelRequest} customStyle={'self-end'}>
                    신청취소
                  </Button>
                ) : (
                  <Button handleClick={() => handleGroupRequest(groupId)} customStyle={'self-end'}>
                    신청하기
                  </Button>
                )
              ) : (
                <Button handleClick={handleChat} customStyle={'self-end'}>
                  채팅창 이동하기
                </Button>
              )}
            </div>
            <div className="studyContent_title mb-3">
              <h1>{_id}에 대한 상세 페이지 레고</h1>
              {/* 그룹 제목 */}
              <h1 className="font-bold text-5xl">{group_name}</h1>
            </div>
            <div className="studyContent_user flex items-center mb-3">
              {/* 그룹장 */}
              <img
                className="rounded-full w-10 h-10 me-3"
                src={import.meta.env.VITE_APP_BACK_URL + profileImgPath}
                alt="유저 프로필 이미지"
              />
              <span className="font-bold text-lg">{leaderName}</span>
            </div>
            <section className="studyInfoWrap md:w-1/2 w-full">
              <ul className="grid md:grid-cols-2 grid-cols-3 gap-2">
                <li className="p-2 flex md:flex-row flex-col items-center gap-2">
                  <Badge color="indigo" size="lg" className="font-bold">
                    카테고리
                  </Badge>
                  <span className="font-semibold">{group_category}</span>
                </li>
                <li className="p-2 flex md:flex-row flex-col items-center gap-2">
                  <Badge color="indigo" size="lg" className="font-bold">
                    목표시간
                  </Badge>
                  <span className="font-semibold">{daily_goal_time}</span>
                </li>
                <li className="p-2 flex md:flex-row flex-col items-center gap-2">
                  <Badge color="indigo" size="lg" className="font-bold">
                    인원
                  </Badge>
                  <span className="font-semibold">
                    {members.length} / {group_maximum_member}
                  </span>
                </li>
              </ul>
            </section>
          </section>

          <div className="studyContent_postContentWrap mb-5">
            <h2 className="text-xl font-semibold">그룹 소개</h2>
            <div className="studyContent_postContent w-full p-5 shadow-md min-h-[200px]">{group_description}</div>
          </div>

          <div className="studyContent_btnWrap self-center">
            {members.includes(userId) &&
              (group_leader === userId ? (
                <Button handleClick={deleteGroup} customStyle={'!bg-danger'}>
                  그룹삭제
                </Button>
              ) : (
                <Button handleClick={leaveGroup} customStyle={'!bg-danger'}>
                  그룹탈퇴
                </Button>
              ))}
          </div>
        </div>
      )}
    </>
  );
}