2024.03.22 TIL - textarea 속성 동적으로 설정하기, 트러블슈팅(query키를 동시에 여러개 무효화하기 - prefix), supabase 열에서 특정 값 빼고 불러오기, 쿼리값 재정렬 후 업데이트하기

Innes·2024년 3월 22일
0

TIL(Today I Learned)

목록 보기
96/147
post-thumbnail

textarea 속성 동적으로 설정하기

// 로그인 상태인 경우의 댓글 등록창

<textarea
  className="text-sm w-[98%] h-[60%] p-2 resize-none"
  placeholder="댓글을 입력해주세요."
  value={comment}
  onChange={handleInputComment}
  />
  • 로그아웃 상태인 경우 해당 textarea에 readOnly 속성을 주고, placeholder 문구도 "로그인이 필요합니다"로 변경하고 싶다.
  • textarea에 동적으로 속성을 주고 싶을 때의 방법은 다음과 같다.
// 로그아웃 상태인 경우

<textarea
  readOnly={!isLoggedIn}
  className="text-sm w-[98%] h-[60%] p-2 resize-none"
  placeholder={
    isLoggedIn ? "댓글을 입력해주세요." : "로그인이 필요합니다."
    }
  value={comment}
  onChange={handleInputComment}
  />

🏹 트러블슈팅

query키를 동시에 여러개 무효화하기

  • 문제 : 댓글 등록, 수정, 삭제 했을 때 댓글 리스트와 댓글 수를 동시에 최신화해야한다! 따라서 mutation했을때 무효화할 queryKey를 동시에 2개를 넣고 싶은데 1개씩 넣으면 잘 되던 무효화가 2개를 동시에 넣으니 둘 중 아무것도 무효화되지 않았다.

  • 기존 코드

  // 댓글 리스트 가져오기 useQuery
  const {
    data: commentsList,
    isLoading: listIsLoading,
    isError: listIsError,
  } = useQuery({
    queryKey: ["commentsList"],
    queryFn: () => getCommentsList(drawingId),
  });

  // 댓글 개수 가져오기 useQuery
  const {
    data: commentsCount,
    isLoading: countingIsLoading,
    isError: countingIsError,
  } = useQuery({
    queryKey: ["commentsCounting"],
    queryFn: () => getCommentsCount(drawingId),
  });

  // 댓글 등록 mutation
  const { mutate: insertCommentMutation } = useMutation({
    mutationFn: async (data: InsertingComment) => {
      const { email, nickname, comment } = data;
      await insertComment({ email, nickname, comment, drawingId });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({
        // ⭐️⭐️ queryKey를 이렇게 2개를 동시에 넣으면 될 줄 알았는데 안됨..
        queryKey: ["commentsList", "commentsCounting"],
      });
    },
  });

⭐️ 해결 : queryKey의 prefix를 활용하자!

(참고 : tanstack-query 공식문서)

  • prefix란?
    • 쉽게 생각하면 컴포넌트에도 부모 컴포넌트, 자식 컴포넌트가 있듯이 queryKey의 부모격이 생기는 것과 유사하다.
    • 체육, 수학, 영어는 '과목'으로 묶이듯이, 여러 queryKey들을 묶는 제목을 따로 만들어줘서 invalidateQueries할 때 queryKey를 보다 더 자유자재로 활용할 수 있게 된다!
    • ex)
      '과목'을 전부 다 무효화시켜줘
      '과목' 중 '체육'만 무효화시켜줘
      등등
  • 해결 : 2개의 queryKey를 연결해주는 prefix queryKey를 만들어주고, 2개를 동시에 invalidateQueries(쿼리키 무효화) 하고싶을 때 해당 prefix만 불러주면 끝!!!
// ✅ Comments.tsx - Palette Ground 프로젝트

  // 댓글 리스트 가져오기
  const {
    data: commentsList,
    isLoading: listIsLoading,
    isError: listIsError,
  } = useQuery({
    // ⭐️⭐️ prefix - "comments", 뒤에는 해당 queryKey의 속성이라고 보면 됨
    queryKey: ["comments", { type: "list" }],
    // queryKey: ["comments", { page: 1 }], 이렇게 해도 됨

    queryFn: () => getCommentsList(drawingId),
  });

  // 댓글 개수 가져오기
  const {
    data: commentsCount,
    isLoading: countingIsLoading,
    isError: countingIsError,
  } = useQuery({
    // ⭐️⭐️ 여기도 역시 prefix - "comments"
    queryKey: ["comments", { type: "count" }],
    // queryKey: ["comments", { page: 2 }], 이렇게 해도 됨

    queryFn: () => getCommentsCount(drawingId),
  });

  // 댓글 등록 mutation
  const { mutate: insertCommentMutation } = useMutation({
    mutationFn: async (data: InsertingComment) => {
      const { email, nickname, comment } = data;
      await insertComment({ email, nickname, comment, drawingId });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({
        // ⭐️⭐️ queryKey가 "comments"인 애들 무효화하기
        // ( = prefix가 "comments"인 애들이 전부 무효화됨)
        queryKey: ["comments"],
      });
    },
  });

📝 요약 정리

  • 문제 : 2개의 queryKey를 동시에 invalidateQueries(무효화)하고싶었는데, queryKey: ["queryKey1", "queryKey2"]로 하면 될 줄 알았더니 둘 다 무효화가 안됨
  • 해결
    • 여러개의 쿼리키를 동시에 무효화시키고 싶을땐 queryKey의 prefix를 사용하면 됨
    • 각각의 queryKey 앞에 "comments"를 붙여주었다.
  • 예시 코드
// useQuery에서
queryKey: ["comments", { type: list }]
queryKey: ["comments", { type: count }]

// mutation onSuccess에서
invalidateQueries({
queryKey: ["comments"]
})

// 앞에 "comments"가 붙은 queryKey들이 동시에 무효화됨

supabase - 열에서 특정 값 빼고 불러오기

  • 로직

    • 1) 그림 상세페이지에서 해당 그림 그린 유저의 다른 그림들을 보여주려 함
    • 2) supabase posts 테이블에서 해당 email이 그린 그림url들만 뽑아서 배열로 반환하기
    • 3) 근데 그 중에 현재 상세페이지에 보여지는 그림은 url배열에서 제외해야함
  • 방법 : .not("drawing_id", "eq", drawingId);

    • 해석 : drawing_id열에서 drawingId와 같은애는 뺀다.
    • "eq": 비교 연산자(여기서는 "equals"를 의미)
      -> drawing_id 필드의 값이 drawingId와 같은 경우를 찾음
      -> 결국, 앞에 not이 붙어있으니까 같은애를 빼라는 뜻
  • 코드

// ✅ painter-api.ts
// posts테이블에서 일치하는 email의 그림 url들을 배열로 반환하기

export const getDrawingUrls = async (
  email: string | null,
  drawingId: number | undefined
) => {
  const { data: urlArray, error } = await supabase
    .from("posts")
    .select("drawing_url")
    .eq("painter_email", email)
    .not("drawing_id", "eq", drawingId);

  if (error) {
    throw error;
  }
  const urls = urlArray.map((urlObj) => urlObj.drawing_url);
  return urls;
};

쿼리값 재정렬 후 업데이트하기

queryClient.setQueryData()

// ✅ Comments.tsx - Palette Ground 프로젝트

  // 쿼리가 완료된 후에 commentsList를 날짜순으로 정렬, 리스트 업데이트(setQueryData)
  useEffect(() => {
    if (commentsList && commentsList.length > 0) {
      const sortedList = commentsList.sort((a, b) => {
        const dateA = new Date(a.created_at);
        const dateB = new Date(b.created_at);
        return dateB.getTime() - dateA.getTime(); // 최신순으로 정렬
      });
      // 정렬된 리스트를 업데이트
      queryClient.setQueryData(["comments", { type: "list" }], sortedList);
    }
  }, [commentsList, queryClient]);
profile
꾸준히 성장하는 우상향 개발자

0개의 댓글