🚀 프로젝트/따꼼

따꼼 트러블 슈팅 | React 프로젝트의 자녀 정보 조회 오류 해결

seheej 2024. 11. 11. 14:17

이번 글에서는 src/query/useChildQuery.ts 파일에서 발생한 오류와 이를 해결하는 과정을 정리합니다. useChildQuery 훅을 사용해 자녀 정보를 불러오는 중에 발생한 문제와 해결 방법을 단계별로 설명합니다.

 

 

오류가 발생했습니다: JSON object requested, multiple (or no) rows returned

 

1. 문제 원인

오류는 다음과 같은 두 가지 주요 원인으로 발생했습니다:

 

1. "use client"; 지시어가 없어서 클라이언트 컴포넌트가 아닌 useChildQuery에서 오류가 발생함

2. single() 메서드를 사용하여 하나의 자녀만 반환하도록 제한했으므로, 다수의 자녀 정보를 가져오는 상황에서 JSON 형식 오류가 발생함

 

2. 해결 과정

1. "use client"; 지시어 추가

  • tanstack query는 클라이언트에서 데이터를 가져오는 작업이므로, useChildQuery를 사용하는 페이지 컴포넌트에서 "use client"; 지시어를 추가해 클라이언트 컴포넌트로 설정했습니다.

2. getChildInfo 함수 수정

  • 여러 자녀 데이터를 가져오기 위해 single() 메서드를 제거하여 다중 행 반환이 가능하도록 변경했습니다.
//수정 전
import { SupabaseDatabase } from "@/types/supabaseDataType";

export const getChildInfo = async (
  client: SupabaseDatabase,
  userId: string
) => {
  const { data, error } = await client
    .from("child")
    .select("*")
    .eq("user_id", userId)
    .single();

  if (error) throw new Error(error.message);

  return data; 
};
// 수정 후
import { SupabaseDatabase } from "@/types/supabaseDataType";

export const getChildInfo = async (
  client: SupabaseDatabase,
  userId: string
) => {
  const { data, error } = await client
    .from("child")
    .select("*")
    .eq("user_id", userId)
    // .single(); 하나만 불러오게 되어있었음

  if (error) throw new Error(error.message);

  return data; 
};

 

3. 자녀 데이터 배열 처리

  • ChildPage 컴포넌트에서는 여러 자녀 정보를 보여주기 위해 반환된 children 데이터를 배열로 처리했습니다.
// 수정 전
"use client";
import ChildCard from "@/components/child/ChildCard";
import RegisterButton from "@/components/child/RegisterButton";
import { useChildInfoQuery } from "@/query/useChildQuery";

const ChildPage = () => {
  const userId = "4c656382-4114-4929-ab84-89ec5a6ddef9"; // 테스트 userId

  const { data: child, isLoading, error } = useChildInfoQuery(userId);

  if (isLoading) return <p>로딩 중...</p>;
  if (error) return <p>오류가 발생했습니다: {error.message}</p>;

  return (
    <div>
      <h1>우리 아이 접종</h1>
      <RegisterButton />
      {child && child.id ? <ChildCard child={child} /> : <p>등록된 아이가 없습니다.</p>}
    </div>
  );
};

export default ChildPage;
"use client";
import ChildCard from "@/components/child/ChildCard";
import RegisterButton from "@/components/child/RegisterButton";
import { useChildInfoQuery } from "@/query/useChildQuery";

const ChildPage = () => {
  const userId = "4c656382-4114-4929-ab84-89ec5a6ddef9"; // 테스트 userId

  const { data: children, isLoading, error } = useChildInfoQuery(userId); // 'child'를 'children'으로 변경

  if (isLoading) return <p>로딩 중...</p>;
  if (error) return <p>오류가 발생했습니다: {error.message}</p>;

  return (
    <div>
      <h1>우리 아이 접종</h1>
      <RegisterButton />
      {children && children.length > 0 ? ( 
        children.map((child) => (
          <ChildCard key={child.id} child={child} /> // map을 사용하여 여러 자녀 데이터 처리
        ))
      ) : (
        <p>등록된 아이가 없습니다.</p>
      )}
    </div>
  );
};

export default ChildPage;

 

  • 주요 변경 사항
    1. child를 children으로 변경: 여러 자녀 정보를 반영하기 위해 변수 이름을 변경
    2. children.length > 0으로 확인: 자녀 배열의 길이를 확인하여, 등록된 자녀가 있는지 체크
    3. map을 사용하여 ChildCard 생성: 배열의 각 자녀에 대해 ChildCard 컴포넌트를 생성하고, key 속성으로 각 자녀의 id를 전달

 

3. 결과

이러한 변경을 통해 다수의 자녀 정보를 오류 없이 가져올 수 있었고, ChildPage 컴포넌트에서 여러 자녀의 접종 정보를 정확하게 표시할 수 있었습니다.

 

4. 배운 점

이번 문제를 해결하면서 다음과 같은 중요한 점을 배웠습니다:

  1. "use client"; 지시어의 중요성
    tanstack query와 같은 데이터 패칭 라이브러리를 사용할 때는 해당 페이지가 클라이언트 컴포넌트여야 하며, 이를 위해 "use client"; 지시어가 필요하다는 점을 확인했습니다. 클라이언트와 서버 컴포넌트의 구분이 필요하고, 특히 클라이언트 상태를 다루는 경우 명확히 클라이언트 컴포넌트로 지정해야 합니다.
  2. .single() 메서드의 올바른 사용
    single() 메서드는 단일 행을 반환할 때 적합하며, 다수의 결과가 필요한 상황에서는 사용하지 말아야 한다는 점을 배웠습니다. 단일 행만 가져오게 되면 여러 데이터를 받아야 할 때 JSON 오류가 발생할 수 있기에, 반환되는 데이터의 양에 따라 .single() 사용 여부를 신중히 결정해야 합니다.
  3. 배열 데이터를 처리할 때의 컴포넌트 구조 설계
    useChildInfoQuery 훅에서 여러 자녀 정보를 반환하게 변경한 후, 컴포넌트에서도 배열 데이터를 적절히 처리할 수 있도록 설계를 수정했습니다. 특히 map()을 사용해 배열을 반복하며 컴포넌트를 렌더링하는 과정에서 key 속성에 유니크한 id를 설정하는 방식이 중요하다는 점을 다시 확인했습니다.
  4. 코드의 확장성
    여러 자녀를 관리하는 구조로 변경함으로써 이후 추가 기능을 구현하거나 데이터를 확장할 때 더 유연하게 대응할 수 있게 되었습니다. 특히 변수명 (child → children)과 데이터 타입의 일관성을 유지하는 것이 중요함을 깨달았습니다.

이러한 학습을 통해 클라이언트-서버 컴포넌트 구분, 데이터 처리 방법, 코드의 확장성에 대한 이해를 높일 수 있었고, 코드 작성 시 발생할 수 있는 오류를 미리 방지할 수 있는 방법도 익히게 되었습니다.