Post

트러블 슈팅: 데이터가 렌더링되지 않는 문제

트러블 슈팅: 데이터가 렌더링되지 않는 문제

트러블 슈팅(Trouble Shooting)

앞선 트러블 슈팅에서는 useEffect가 무한루프 되는 문제를 다루었다. 이번에는 무한루프를 해결하기 전에 발견했던, 데이터가 페이지에 렌더링 되지 않는 문제를 트러블 슈팅 하려고 한다.


문제 인식

페이지에 데이터가 업로드 되지 않는 문제

리팩토링을 하면서 페이지에 접속했을 때 여행지 리스트가 렌더링 되지 않는 문제가 발생했다.

여행지 데이터를 받아오는 fetch 함수는 검색 키워드(searchQueryParams)와 사용자가 선택한 카테고리(selectedCategory)를 매개변수로 하는 getfilteredResult함수이다.

이 함수는, 함수의 인자를 참조하는 useEffect가 호출하고 있었다. 이에 따라 fetch 함수의 실행과정을 점검하고 가설을 세워 원인을 파악하고자 했다.

가설 설정 및 검증

가설 1. useEffect가 제대로 실행되지 않았다.

가설 검증하기: console.log로 디버깅

  • 첫번째로 검증한 가설은 useEffect가 실행되지 않았다는 가설이다. 관련 코드는 다음과 같다.

    여기에 console.log('destinations')를 추가하여 useEffect가 실행되는지 확인했다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    useEffect(() => {
      getCategoryIdList();
      getfilteredResult(searchQueryParams, selectedCategory);
      console.log("debug useDestinationsFetch useEffect"); //디버깅을 위해 추가한 line
    }, [
      getCategoryIdList,
      getfilteredResult,
      searchQueryParams,
      defaultCategoryIdList,
    ]);
    
  • 나는 이 문제의 원인으로 useEffect가 호출되지 않는 경우를 염두했다. 그러나 콘솔창에서 로그를 확인한 결과, 예상과 정 반대로 useEffect는 무한 루프로 호출되고 있었다.

    이에 따라 무한 루프 문제를 먼저 해결한 후, 데이터가 렌더링 되는지 다시 확인했다.

    그 결과, useEffect가 정상 실행되어도 데이터는 렌더링 되지 않았다. 따라서 문제를 해결하기 위한 새로운 가설을 세웠다.



가설 2. fetch 함수에 필요한 인자가 정상적으로 전달되지 않았다.

가설 검증하기: getfilteredResult에 인자로 전달되는 searchQueryParams와 selectedCategory 점검하기

  • 가설1를 검증하면서 getfilteredResult 함수와 useEffect 자체는 잘 실행되고 있는 점을 확인했다.

    이에 따라 ‘fetch 함수에 인자가 제대로 전달되지 않았다’는 두번째 가설을 설정했다.

    이 가설을 검증하기 위해, fetch 함수 getfilteredResult에 인자가 제대로 전달되는지 점검했다.


  • 우선 인자로 전달되는 searchQueryParamsselectedCategory에 값이 담겨있는지 확인했다.

    각 인자를 참조하는 useEffect를 등록하고 console.log로 인자들을 디버깅했다.


1
2
3
4
useEffect(() => {
  console.log("selectedCategory", selectedCategory);
  console.log("searchQueryParams", searchQueryParams);
}, [selectedCategory, searchQueryParams]);


  • 콘솔창을 확인한 결과, selectedCategory에 사용자가 선택한 카테고리의 id가 담기지 않는다는 사실을 알게 되었다.


useEffect Console Image


  • 이를 토대로 selectedCategory가 원인일 가능성을 높게 두어, 관련 코드를 분석하였다.




문제 해결하기: selectedCategory 관련 로직 분석하기

  • selectedCategory는 useCateogry 커스텀 훅에서 상태관리하는 값이었다.

    따라서, 다음과 같이 useCategory 커스텀 훅에 콘솔 로그를 실행하는 useEffect를 추가하여 카테고리 데이터가 상태관리 되고 있는지 확인했다.


1
2
3
useEffect(() => {
  console.log("카테고리 커스텀 훅의 selectedCategory", selectedCategory);
}, [selectedCategory]);


  • 앞서 인자들을 확인하기 위해 등록했던 useEffect와 동시에 실행하고자, 각 데이터가 위치한 커스텀 훅을 구별할 수 있는 문자열을 추가하고 다시 한 번 코드를 실행하였다. 그리고 다음과 같이, 직접 로컬환경에서 카테고리를 선택하며 콘솔 로그를 확인했다.


Category Console Image


위 과정을 토대로, useCategory 훅의 selectedCategory가 변경되어도 useDestinations 훅의 selectedCategory에는 반영되지 않는 점을 파악했다. 이에 따라, 원인을 파악하고자 우선 공식문서에서 커스텀 훅의 동작 원리를 확인했다.

React Dev Document Image

https://react.dev/learn/reusing-logic-with-custom-hooks#custom-hooks-let-you-share-stateful-logic-not-state-itself

공식문서를 확인한 결과, 새로운 사실을 알게 되었다.

커스텀 훅은 로직의 재사용성을 높이기 위해 이용하는 개념이며, state를 공유할 수 없었다.

은연중에 커스텀 훅의 state가 변하면 이를 사용하는 다른 컴포넌트도 리렌더링되면서 함께 변할 것이라 생각했었다. 즉, 나는 커스텀 훅과 이 커스텀 훅의 state를 사용하는 컴포넌트의 관계를, 부모 - 자식 컴포넌트 관계와 혼동하고 있었던 것이다.

이는, 공식문서에서 설명하는 커스텀 훅의 의의에 대해 알고 있지 않았기 때문이다. 따라서 공식문서에서 커스텀 훅의 개념을 설명하는 부분을 정독하고 state 대신 로직을 공유하도록 커스텀 훅을 수정했다.




문제 해결하기: useCategory, useDestinations 커스텀 훅 수정하기

  • 공식문서를 토대로 커스텀 훅은 로직을 공유하는 목적으로 사용되는 개념임을 이해했다.

    따라서, useDestinations 커스텀 훅이 useCategory 커스텀 훅을 호출하여 selectedCategory의 값을 받아오던 로직을 수정했다.

    대신, selectedCategory를 useDestinations 커스텀 훅의 인자로 받게 하여 useDestinations 커스텀 훅을 호출할 때 selectedCategory가 반드시 필요하도록 바꾸었다.

    세부 코드는 다음과 같다.


  • 기존 useDestinations 코드
1
2
3
4
5
6
7
8
9
10
11
12
function useDestinations() {
  const { selectedCategory } = useCategory();

  const getfilteredResult = useCallback(
    async (searchQueryParams: string, selectedCategory: number[]) => {
      /* 여행지 리스트 데이터를 fetch하는 세부로직  */
    },
    [
      /* 의존성 배열 */
    ]
  );
}


  • 수정된 useDestinations 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function useDestinations(selectedCategory: number[]) {
  const getfilteredResult = useCallback(
    async () => {
      /* 여행지 리스트 데이터를 fetch하는 세부로직  */
    },
    [
      /* 의존성 배열 */
    ]
  );

  ...

  return { destinations, totalDestinationsCount };
}


  • useDestinations 커스텀 훅 호출
1
2
const { destinations, totalDestinationsCount } =
  useDestinations(selectedCategory);


커스텀 훅으로 상태를 공유하지 않고 로직을 재사용하는 용도로 코드를 수정한 결과, 여행지 리스트가 정상적으로 출력되었다.

React Dev Document Image



고찰

커스텀 훅으로 state를 공유할 수 없다는 점을 새롭게 알게되었다. 무엇보다 트러블 슈팅을 할 때, 원인을 명확히 파악하고 공식문서를 우선 확인하는 방식이 명확한 정보로 문제를 개선할 수 있는 방법임을 확인했다.

앞으로도 트러블 슈팅은 원인파악, 공식문서 확인을 1차 과정으로 둘 생각이다.

This post is licensed under CC BY 4.0 by the author.