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

작성자 없음

작성자 정보가 삭제된 글입니다.

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

31-08-basic-promise-all / image-upload-submit-promise-all

같은 API 두 번 요청을 합니다.

작성

·

870

0

크롬 개발자 도구에서 페이로드 확인을 하면 fetchBoards가 두번 요청을 합니다.

시작점을 확인을 해보면 createUploadLink.js에서 빈 값으로 요청을 하고

두 번째 요청에서는 제대로 index.tsx에서 값을 넣고 refetch를 진행을 합니다.

createUploadLink.PNGfetchBoards가 1,3번 이고 fetchBoardsCount가 2번 입니다.

사용하는데 있어 아무런 문제 없이 사용이 가능한데 왜 이런 현상이 있는지 해결을 하고 싶습니다.

 

첫 마운트가 되거나 API요청을 하면 불필요한 fetchBoards, fetchBoardsCount가 createUploadLink.js에서 요청이 가는데

ApolloClient Setting 부분에서 요청이 가는 걸 확인 했습니다.

const uploadLink = createUploadLink({
    uri: "http://backend-practice.codebootcamp.co.kr/graphql",
  });

  const client = new ApolloClient({
    link: ApolloLink.from([uploadLink]),
    cache: new InMemoryCache(),
  });

 

refetch하는 전체 코드입니다.

// test - refetch 문제
export default function Hom(): JSX.Element {
  const { data, refetch } = useQueryFetchBoards();
  const { data: dataBoardsCount, refetch: refetchBoardsCount } =
    useQueryFetchBoardsCount();
  const router = useRouter();
  const render = useRef(false);

  useEffect(() => {
    // 첫 마운트 실행 막음
    if (!render.current) {
      render.current = true;
      console.log("처음 실행됨");
      return;
    }

    const search = String(router.query.search);
    const page = Number(router.query.page) || 1;
    if (search === "undefined") {
      void refetch({ page });
      console.log("검색X");
    } else {
      void refetch({ page, search });
      void refetchBoardsCount({ search });
      console.log("검색O");
    }
    console.log("Hom Search: ", search);
  }, [router.query]);

  return (
    <>
      <SearchBar />
      {data?.fetchBoards.map((el, index) => (
        <div key={index}>{el.title}</div>
      ))}
      <Pagination count={dataBoardsCount?.fetchBoardsCount} />
    </>
  );
}

여기서 <SearchBar /> , <Pagination />는 router.push에서 query로 ?search= , ?page= 쿼리스트링 만드는 역할만 하고 있고 전체 부모 컴포넌트에서 useEffetch로 refetch하고 있습니다.

"next": "13",

"react": "^18.2.0",

"apollo-upload-client": "^17.0.0",

입니다.

답변 2

0

노원두님의 프로필 이미지
노원두
지식공유자

안녕하세요! 초무님!

해당 문제는 요청을 보내기 시작한 Hom 컴포넌트가 새롭게 리렌더 되면서 발생하는 문제예요!

여기서 말하는 리렌더는, Hom 컴포넌트 내부가 다시 그려지는 것이 아닌, Hom 컴포넌트 상단에서 Hom 컴포넌트를 통째로 없앴다가 다시 나타내고 있는 문제랍니다!
그러므로 요청에 대한 응답이 오기 전에 컴포넌트가 사라져버리니 전송된 요청이 취소되면서 에러가 발생하는 것이지요!

 

해당 문제를 더 자세히 파헤치기 위해서는, 컴포넌트 상단에 존재하는 Layout, Apollo-Setting 등의 컴포넌트에서 하위 children을 리렌더하는지 점검해 보실 필요가 있을 것 같아요!
(Layout이 약간 의심스러워요!)

 

위와 같은 문제가 발생했을 때, 가장 일반적인 접근법으로 현재 필요하지 않는 모든 부분은 주석을 걸고, 주석을 하나씩 풀면서 어떤 부분에서 하위 children을 리렌더하는지 검증해 보는 방식으로 찾아내는게 좋을 것 같네요!^^

 

아직 잘 뭐가 문제인지 모르겠습니다.

Layout, Apollo-Setting 모두 리렌더 하고 있고 Layout 또한 제거하고 해도 똑같습니다.

 

일반적으로 이벤트 함수에 refetch를 하면 문제 없이 해당 컴포넌트 시작 점으로 한 번만 API 요청을 하는데

next 모듈인 useRouter를 사용하고 useEffect로 router.query 값이 변경이 되면 refetch 하도록 하면 API 요청 시작 점이 Apollo-Setting과 해당 index 컴포넌트로 요청이 갑니다.

또한 컴포넌트에서 API 요청 없이 리렌더링이 일어나도 Apollo-Setting에서 요청이 갑니다.

보니까 useQuery를 사용한 것만 요청을 합니다.

(FetchBoards, FetchBoardsCount 사용하면 2개 모두 요청을 합니다.)

그래서 쿼리 파라미터를 사용을 제대로 사용하고 있는 걸까요?

여러 번 해보니까 useQuery를 사용하면 Apollo-Setting에서 API 요청을 하는 것 같습니다.

단순히 해당 index의 page 컴포넌트만 리렌더링이 일어나면 문제 없지만

router.push로 리렌더링이 일어나면 해당 page 컴포넌트만 리렌더링이 일어나는게 아니라 _app 컴포넌트 전체가 리렌더링이 일어나 또 Apollo-Setting에서 API 요청을 하고

router.query의 값이 변경이 되면 useEffect로 refetch를 하니 page 컴포넌트에서 해당 값이 들어간 API 요청으로 총 2번의 API 요청이 되는 걸 확인 했습니다.

 

정리하자면

  1. useQuery를 사용하면 렌더링 될 때마다 Apollo-Setting에서 API 요청이 가는데 초기 값으로 data를 가져옵니다.

  2. 여기서 router.push의 query값으로 refetch를 하는데 router.query가 변경이 되면

    useEffect를 실행하도록 했습니다.

  3. 강사님 말씀대로 해당 컴포넌트에서만 리렌더링이 아닌 전체 _app 컴포넌트에서 부터

    리렌더링이 일어나다 보니 다시 ApolloClient에서 API 요청이 가고 그 뒤에 다 마운트 되면 useEffect 안 refetch API가 보내진 것 이였습니다.

 

혹시 이러한 문제를 해결할 방법이 있을 까요??

0

안녕하세요, 인프런 AI 인턴입니다.

전찬호님, 문의하신 내용에 대해 답변 드리겠습니다. 클라이언트 사이드에서 GraphQL API를 두 번 요청하는 현상에 대한 문제 해결을 원하신다고 이해했습니다. 제공해 주신 정보를 바탕으로 몇 가지 가능한 원인과 해결방법에 대해 알려드리겠습니다.

  1. 빈 값으로 요청이 발생하는 경우: 컴포넌트가 처음 마운트될 때 빈 값으로 API 요청이 전송될 수 있습니다. 이는 useQueryFetchBoards 훅에 의해 초기 데이터를 가져오기 위한 요청이 있을 수 있기 때문입니다. 초기 데이터가 필요 없다면 skip 옵션을 사용하여 초기 요청을 건너뛸 수 있습니다.

  2. refetch 시에 두 번째 요청이 발생하는 경우: useRouter().query 값의 변화에 따라 useEffect 내부에서 refetch 함수가 실행되고 있습니다. 이와 같이 라우터 쿼리의 변경을 감지하여 refetch를 실행하면 해당 API의 재요청이 정상적으로 발생합니다.

  3. Apollo Client 설정 문제: createUploadLink를 사용할 때 HTTP 요청이 초기 설정 시에 발생할 수 있습니다. 생성한 링크는 클라이언트 초기화 단계에서 설정되기 때문에 네트워크 요청과 관련된 부수 효과가 있을 수 있습니다. 이와 관련한 자세한 로깅이나 요청 타이밍을 확인해 볼 필요가 있습니다.

  4. 개발자 도구에서 확인한 네트워크 요청: 로그에 따르면 createUploadLink.js에서 빈 값으로 요청하고 있으니, 이 파일 내부의 로직에서 조건을 걸어 불필요한 요청이 발생하지 않도록 처리가 필요해 보입니다.

추가로, 한 번의 비동기 처리를 위해 void를 사용하고 계신 것으로 보입니다. void를 사용하지 않고도 await 또는 .then()과 같은 방법으로 비동기 처리를 할 수 있습니다.

이러한 문제를 해결하기 위해서는 요청을 실행하는 useQuery의 옵션을 조정하거나, 요청 자체의 조건을 검토해볼 필요가 있습니다. 또한, createUploadLink 함수의 호출 타이밍을 점검하면서 실제 네트워크 요청이 언제 일어나는지 확인해 보시길 권장드립니다.

참고하셔서 문제 해결에 도움이 되시길 바랍니다.

작성자 없음

작성자 정보가 삭제된 글입니다.

질문하기