인프런 커뮤니티 질문&답변

bo9999님의 프로필 이미지
bo9999

작성한 질문수

Next + React Query로 SNS 서비스 만들기

로그인과 회원가입 실제로 하기

찜하기 관련 질문드립니다.

작성

·

164

0

안녕하세요 상세페이지에서 찜하기 요청을 하게되면 users/favorite/${peopleId}로 post 요청을 보내게되고 그럼 users/favorite api에 찜한 사람들의 목록이 추가됩니다.

찜하기를 눌렀을경우 아이콘의 컬러를 변경시켜야해서 getQueryData로 찜한 사람들의 목록 을 가져오려고 하였는데

  const { data: likePeopleList } = useQuery<GetPeoples>({
    queryKey: ["get", "likepeoples"],
    queryFn: getLikePeoples,
    staleTime: 60 * 1000, // fresh -> stale, 5분이라는 기준
    gcTime: 300 * 1000,
  });

위에 코드가 없으면 likeQuery를 가져오지 못하고있는것같습니다. getQueryData로 가져오는 방법이 잘못된걸까요? 다른 좋은 방법있다면 여쭤보고싶습니다.

밑에는 전체 코드입니다.


type Props = {
  peopleId: string;
};

export default function PeoplePosts({ peopleId }: Props) {
  const { data } = useQuery<
    GetPeoplePost,
    Object,
    GetPeoplePost,
    [_1: string, _2: string, _3: string]
  >({
    queryKey: ["get", "peoplesDetail", peopleId],
    queryFn: getPeopleDetail,
  });

  const { data: likePeopleList } = useQuery<GetPeoples>({
    queryKey: ["get", "likepeoples"],
    queryFn: getLikePeoples,
    staleTime: 60 * 1000, // fresh -> stale, 5분이라는 기준
    gcTime: 300 * 1000,
  });

  const {
    content,
    nickname,
    userFileUrl,
    favoriteCount,
    viewCount,
    softSkill,
    techStack,
    links,
    position,
    alarmStatus,
    year,
  } = data?.data ?? {};

  const queryClient = useQueryClient();

  const likeQuery = queryClient.getQueryData<GetPeoples>([
    "get",
    "likepeoples",
  ]);
  console.log("likeQuery", likeQuery);

  const liked = !!likeQuery?.data.find(
    (item) => item.userId === Number(peopleId),
  );

  console.log("liked", liked);

  const like = useMutation({
    mutationFn: (peopleId: string) => {
      return fetch(
        `${process.env.NEXT_PUBLIC_BASE_URL}/users/favorite/${peopleId}`,
        {
          method: "post",
        },
      );
    },
    onMutate(peopleId: string) {
      const oldData = queryClient.getQueryData<GetPeoples>([
        "get",
        "likepeoples",
      ]);
      if (oldData) {
        const newData = {
          ...oldData,
          data: oldData.data.map((item) => ({
            ...item,
            userId: Number(peopleId),
          })),
        };
        queryClient.setQueryData(["get", "likepeoples"], newData);
      }
    },
  });

  const unLike = useMutation({
    mutationFn: (peopleId: string) => {
      return fetch(
        `${process.env.NEXT_PUBLIC_BASE_URL}/users/favorite/${peopleId}`,
        {
          method: "delete",
        },
      );
    },
    onMutate(peopleId: string) {
      const oldData = queryClient.getQueryData<GetPeoples>([
        "get",
        "likepeoples",
      ]);
      if (oldData) {
        const deleteData = {
          ...oldData,
          data: oldData.data.filter((item) => item.userId !== Number(peopleId)),
        };
        queryClient.setQueryData(["get", "likepeoples"], deleteData);
      }
    },
  });

  const onLike: MouseEventHandler<HTMLButtonElement> = (e) => {
    e.preventDefault();
    if (liked) {
      unLike.mutate(peopleId);
    } else {
      like.mutate(peopleId);
    }
  };

  return (
    <div className="flex flex-col">
      <div className="flex flex-col gap-4 border-b pb-10">
        <div className="flex items-center gap-[10px]">
          <Image
            src={`${userFileUrl}`}
            alt="유저프로필"
            width={30}
            height={30}
          />
          <h1 className="text-[32px] font-bold">{nickname}</h1>
          <div>
            <BlueTextBox textSize="12px" textToShow={`${position}`} />
          </div>
        </div>
        <div className="flex flex-col gap-2">
          {softSkill
            ?.split(",")
            .map((skill, i) => <HashTag text={skill} key={i} />)}
        </div>
        <div className="flex gap-3">
          <HeartEyeIconBox count={favoriteCount as number} icon={heartIcon} />
          <HeartEyeIconBox count={viewCount as number} icon={eyeIcon} />
        </div>
      </div>
      <div className="mt-[42px] flex flex-col gap-[50px]">
        <div className="people-post-grid">
          <h1 className="text-[22px] font-bold">경력</h1>
          <h3>{year}</h3>
        </div>
        <div className="people-post-grid">
          <h1 className="text-[22px] font-bold">사용언어</h1>
          <div className="flex gap-2">
            {techStack
              ?.split(",")
              .map((stack, i) => (
                <TechStack techStack={stack} showText key={`stack${i}`} />
              ))}
          </div>
        </div>
        <div className="flex flex-col gap-3">
          <h1 className="text-[22px] font-bold">자기소개</h1>
          <p>{content}</p>
        </div>
        <div className="flex flex-col gap-3">
          <h1 className="text-[22px] font-bold">Link</h1>
          <Link href={links as string}>{links}</Link>
        </div>
      </div>
      <div className="mt-[60px] flex gap-[13px] self-center">
        <button
          className={`h-[58px] w-[142px] rounded-md bg-neutral-orange-500 font-bold ${alarmStatus ? "text-neutral-white-0" : "text-neutral-black-800"}`}
        >
          {alarmStatus ? "제안하기" : "제안불가"}
        </button>
        <button
          onClick={onLike}
          className="flex h-[58px] w-[58px] flex-col items-center justify-center rounded-md border"
        >
          {liked ? (
            <Image
              src={fillHeartIcon}
              alt="하트아이콘"
              width={20}
              height={20}
            />
          ) : (
            <Image src={heartIcon} alt="하트아이콘" width={20} height={20} />
          )}
          <h5 className="text-[12px]">{favoriteCount}</h5>
        </button>
      </div>
    </div>
  );
}

답변 1

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

getQueryData는 한 번이라도 같은 키로 useQuery나 setQueryData로 해당 키가 생성되어야 사용할 수 있습니다. 아마도 useQuery/setQueryData를 이전에 하신 적이 없을 겁니다.

bo9999님의 프로필 이미지
bo9999

작성한 질문수

질문하기