커스텀 훅 리팩토링 기록

이승훈·2023년 7월 29일
1

시행착오

목록 보기
12/23

급하게 구현하며 비대해져버린 기능의 커스텀 훅을 분리 하였다.

문제

커뮤니티(게시판) 기능 구현 중 발생
게시글의 하단에는 해당 게시글의 태그들을 통해 불러온 관련게시글들이 보이게 된다.

처음 게시그화면에 들어가면 내 글이 안나온다.

아래의 관련게시글을 통해 들어가면 해당 게시글이 관련게시글목록에 보인다.

즉, 처음 게시글로 들어가면 관련게시글에 현재 게시글이 없는데
관련게시글로 타고 들어가면 관련게시글에 현재 게시글이 보인다.

이것을 해결하고자 하였다.

원인

아래의 코드는 태그항목에 따라 게시글을 불러오는 custom Hook 이다.

const useTagSearchFeedPostList = ({
  feedPostCode,
  feedTags,
  postCount,
}: Props) => {
  const [currentFeedTag, setCurrentFeedTag] = useState(feedTags ?? '전체');
  const { showBasicModal } = useBasicAlert();
  const [cumulativeFeedPostList, setCumulativeFeedPostList] = useState<
    FeedPostListType | undefined
  >();

  const [getTagSearchFeedPostList] = useLazyQuery(TagSearchFeedPostListQuery);

  const getFeedList = async (isRefresh: boolean) => {
    const feedPostListData = await getTagSearchFeedPostList({
      variables: {
        orderInput: {
          orderBy: 'CREATEDAT',
          orderDirection: 'DESC',
        },
        tagNames: currentFeedTag === '전체' ? null : currentFeedTag,
        paginationInput: {
          take: postCount ?? 3,
          after: isRefresh ? null : cumulativeFeedPostList?.cursor,
        },
        feedPostCode: feedPostCode,
      },
      fetchPolicy: 'no-cache',
      onError: () => {
        showBasicModal({ title: '네트워크 에러' });
      },
    });

    const isEmptyFeedPosts =
      feedPostListData.data.tagSearchFeedPostList.totalCount === 0;

    if (isEmptyFeedPosts) {
      setCumulativeFeedPostList(feedPostListData.data.tagSearchFeedPostList);
      return;
    }

    if (isRefresh) {
      setCumulativeFeedPostList(feedPostListData.data.tagSearchFeedPostList);
      return;
    }

    if (cumulativeFeedPostList && !isRefresh) {
      feedPostListData.data.tagSearchFeedPostList.feedPosts.unshift(
        ...cumulativeFeedPostList.feedPosts,
      );
      setCumulativeFeedPostList(feedPostListData.data.tagSearchFeedPostList);
      return;
    }

    setCumulativeFeedPostList(feedPostListData.data.tagSearchFeedPostList);
  };

  const [refreshing, setRefreshing] = useState(false);

  useFocusEffect(
    useCallback(() => {
      getFeedList(true);
    }, [currentFeedTag]),
  );

  useEffect(() => {
    getFeedList(true);
  }, [currentFeedTag]);

  const onRefresh = useCallback(() => {
    setRefreshing(true);

    setTimeout(async () => {
      getFeedList(true);
      setRefreshing(false);
    }, 1500);
  }, [currentFeedTag]);

  const feedPostListData = cumulativeFeedPostList;

  return {
    feedPostListData,
    currentFeedTag:
      typeof currentFeedTag === 'string' ? currentFeedTag : '전체',
    setCurrentFeedTag,
    refreshing,
    onRefresh,
    getFeedList,
  };
};

export default useTagSearchFeedPostList;

위의 커스텀훅은 한번에 너무 많은 일을한다.
1. 유저가 선택한 태그종류에 따라 다른 게시글 목록을 불러온다.
2. 한번에 여러개의 피드태그들이 배열의 형태로 들어오면 여러개의 태그종류에 따른 게시글 결과를 불러온다.
3. after가 있는 상태로 요청이 들어올 경우 기존의 목록의 뒤를 이어 새로운 게시글들을 추가해준다.
4. refresh가 일어난 경우 현재 게시글목록을 다 없애고 새로운 게시글 목록을 불러온다.

한번에 여러 기능을 하다보니 버그가 발생했을 때 그 원인을 찾고 해결하기가 어려웠다.
이번의 문제상황에서의 원인은 다음과 같았다.

  1. 이 커스텀훅에서 반환하는 cumulativeFeedPostList를 통해 관련된 게시글을 받는다.
  2. 커스텀훅이 실행될 때 인자로 받는 feedPostCode를 통해 getFeedList함수는 현재 게시글을 서버에 알린다.
  3. 서버는 해당하는 현재 게시글을 제외한 채로 관련된 게시글들을 돌려준다.
  4. 근데 두번째로 타고들어간 게시글에서 서버는 현재 게시글이 아닌 이전의 게시글아이디를 받고있었다.

원인이 발생한 이유는 도저히 못찾았다.
추론하기로는 useLazyQuery를 통해 반환된 getTagSearchFeedPostList 함수가 캐싱되는것이 아닌가라고 추론해보곤 있지만 추론을 증명할 방법을 못찾았다.

애초에 게시글 목록 스크린에서 새로고침하고 아래로 스크롤 했을 때 누적으로 게시글들을 쌓아서 반환하기 위한 목적으로 만든 커스텀훅이었다.

그러니 여러개의 태그들을 받는다는건 초창기 커스텀훅을 작성 시 고려하지 않았고
또한 feedPostCode를 받는다는것도 고려하지 않았었다.

문제의 원인을 근본적으로 해결하면서 너무 비대해진 커스텀훅을 가볍게 만들고 역할을 분리해주는 방법을 선택하였다.

해결

interface Props {
  feedPost: FeedPostType;
}

const useGetRelatedFeedPost = ({ feedPost }: Props) => {
  const { showBasicModal } = useBasicAlert();
  const feedTags = feedPost.feedTags.map((tagInfo) => tagInfo.tagName);

  const { data, loading } = useQuery<GetTagSearchFeedPostListType>(
    TagSearchFeedPostListQuery,
    {
      variables: {
        orderInput: {
          orderBy: 'CREATEDAT',
          orderDirection: 'DESC',
        },
        tagNames: feedTags,
        paginationInput: {
          take: 3,
        },
        feedPostCode: feedPost.code,
      },
      fetchPolicy: 'no-cache',
      onError: () => {
        showBasicModal({ title: '네트워크 에러' });
      },
    },
  );

  const isRelatedFeedPostExist =
    data?.tagSearchFeedPostList.feedPosts.length !== 0;

  const relatedFeedPost = isRelatedFeedPostExist
    ? data?.tagSearchFeedPostList
    : undefined;

  return { relatedFeedPost, loading };
};

export default useGetRelatedFeedPost;

아예 관련된 게시글을 얻기위한 커스텀훅을 새로 작성하였다.
해당 훅에선 게시글 목록을 state로 관리하는것이 아닌 서버에서 받아온 데이터를 바로 return 해준다.

또한 useLazyQuery를 사용할 때 데이터를 요청하는 함수가 캐싱될것이라는 가능성을 배재하기 위해 useQuery를 사용하여 바로 즉각적으로 아주 그냥 직접적으로 데이터를 요청하며, fetch-policy를 no-cache로 설정하여 그냥 캐싱에 대한 모든 가능성을 배재시키기 위해 코드를 작성하였다.

뭐 일단 이러한 단계를 통해 문제는 해결되었다.
허나 명확한 원인을 파악하지 못한 찝찝함은 남아있다.
근데 뭐 어뜩해 일단 기간 맞춰서 개발하려면 넘어가야지.
이렇게 또 부채가 쌓여간다...
허나 부채도 자산......

내가 짠 코드를 오픈하는건 참 부끄러운 일이다.
하지만 따끔한 피드백을 받을 수 있다면 부끄러움 쯤이야.

profile
Beyond the wall

2개의 댓글

comment-user-thumbnail
2023년 7월 29일

감사합니다. 이런 정보를 나눠주셔서 좋아요.

1개의 답글