inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

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

회원가입 실제로 하기

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

214

작성자 없음

작성한 질문수 0

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>
  );
}

react next.js react-query next-auth msw

답변 1

0

제로초(조현영)

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

캡처링부분 질문있습니다.

0

76

2

깃에 소스코드를 찾을 수 없습니다.

0

114

2

useInfiniteQuery promise와 react use 사용시 페이지 무한 로딩

0

98

1

import 파일 경로를 찾지 못 해서 에러가 발생합니다.

0

111

2

css 라이브러리 추천 부탁드립니다

0

141

2

팔로우 추천 목록이 빈 배열로 들어옵니다.

0

133

1

게시물 업로드 시 userId가 undefined로 들어가는 오류

0

119

1

useSuspenseQuery 사용 시 SSR 401 이슈 관련

0

173

1

리액트 쿼리 useinfinitequery 무한스크롤 구현 시 페이지가 이동할 경우 데이터가 보존되게 할 수 있나요??

0

186

3

폴링이 필요없는 이유

0

93

2

next Request Memoization과 react cache

0

110

2

seo 최적화 기준은 데이터 fetching인가요 아님 데이터 렌더링인가요?

0

84

2

next.js 서버fetch 에러 fallback ui 구현 방법

0

173

2

프레임워크 여론 파악법

0

125

2

필터옵션이 많은 페이지에서 서버 fetch를 하는게 맞는걸까요??

0

103

2

서버 fetch suspense 로 감싸고 새로고침 시 잠시 빈 화면이 노출된 후 fallback ui가 노출됩니다.

0

102

2

template.tsx 내 서버fetch 응답값과 클라이언트 컴포넌트 상태값 싱크가 맞지 않는 이슈

0

66

2

Auth.js 사용 시 authorize 함수가 호출되지 않습니다

0

132

2

next.js 에서 로그인에 관하여

0

139

1

Next의 route handler에 대한 질문이 있습니다.

0

101

2

게시판 리스트 만들때 use client를 어디서부터 집어넣어야할지 모르겠습니다

0

99

2

프라이빗 폴더를 해야 하는 이유가 모호한 것 같아요.

0

85

2

vanilla-extract 못찾는 문제

0

230

2

fetch 캐싱과 revalidate 관련

0

86

2