본문 바로가기

트러블 슈팅/React

[react-query] 실행 시점 enabled, refetch를 이용하고, cache된 데이터 삭제

문제 발생

- 닉네임을 입력하고, 초대를 누르고 해당 닉네임이 있다면 닉네임이 나옵니다. 처음에 똑같은 닉네임을 검색했다면, 초대 버튼을 누르지 않아도 리스트에 닉네임이 표시되는 문제점이 발생하였습니다. 

 

처음 사용자 초대
초대 버튼을 누르지 않았는데, 사용자가 보여지는 문제

 

 

- 로직에서 enabled를 이용하여 초대 버튼을 클릭시 enabeld가 true가 되며, useEffect를 이용하여 데이터가 변경되면 enabled가 false가 되게 처리하였습니다. 하지만 useEffect를 제거하고 로직을 개선의 필요성을 느꼈습니다.

//enabled를 이용한 기존 코드
const useGetUser = ({ q, enabled }: { q: string, enabled: boolean }): UseQueryResult<User> => {
  return useQuery([USER_API_KEY.USER, { q }], () => getUser({ q, enabled }), {
    suspense: true,
    enabled
  });
};

export default useGetUser;
//useEffect를 이용하여 enabled 처리
const [enabled, setEnabled] = useState(false);
const { data: userData } = useGetUser({ q: inputValue , enabled });

  const handleClickSearch = useCallback(() => {
    setEnabled(true)
  }, []);
  
  useEffect(() => {
    setEnabled(false);
  }, [userData]);

 

여기서 잠깐! 왜 useEffect를 사용하지 않으려고 할까?

useEffect()를 사용하면 네트워크 또는 브라우저 DOM과 같은 외부 시스템을 동기화할 수 있습니다! 근데, props나 state가 변경되어서 컴포넌트이 state를 업데이트하는 경우가 아니라면 굳이 useEffect()는 필요하지 않습니다.

useEffect()를 사용하지 않았을 때 나오는 이 점은 코드가 더 빨라지고(추가적인 '계단식' 업데이트를 피함), 더 간단해지고(일부 코드 제거), 오류가 덜 발생한다.(서로 다른 state 변수가 서로 동기화 되지 않아 발생하는 버그를 피함)

 

현재 코드를 보았을 때, useEffect를 이용하여 data를 제어하는게 아니라, 이벤트 핸들러를 통해서 데이터를 제어하는게 옳다고 판단하여 useEffect를 제거하였습니다.

 

Effect에 관한 자세한 내용은 따로 정리해놓았습니다! 아래 링크를 통해서 확인해주세요

 

[React] useEffect()를 제거해보자!

effect를 제거했을 때 이점 코드를 더 쉽게 따라갈 수 있고, 실행 속도가 빨라지며, 오류 발생 가능성이 줄어든다. 불필요한 Effect를 제거하는 방법 1. 렌더링을 위해 데이터를 변환하는 경우 - 렌더

dev-logbook.tistory.com

 

해결 방법

- useEffect를 제거하기 위해서 enabled=false 처리를 하였으며 refetch()를 이용하여, 초대 버튼을 클릭 시 데이터를 받아오는 형식으로 제작하였습니다.  enabled를 false처리하는 이유는 처음 데이터를 받아오는 것을 방지하고자 사용하였습니다. 그리고, 초대 버튼 클릭 시에만 데이터를 받아오고 싶어서 refetch()를 이용하였습니다.

//처음에 데이터받아오는 것을 방지하고 enabled는 false 처리
const useGetUser = ({ q }: { q: string }): UseQueryResult<User> => {
  return useQuery([USER_API_KEY.USER, { q }], () => getUser({ q }), {
    suspense: true,
    enabled: false,
  });
};

export default useGetUser;
const { data: userData, refetch } = useGetUser({ q: inputValue });

  const handleClickSearch = useCallback(() => {
    refetch();
  }, []);

 

 

- 처음 검색했던 사용자가 초대 버튼을 누르지 않았음에도, 계속 리스트에 표시되었던 이유는 data가 cache되었기 때문입니다. 그래서cache된 데이터를 삭제하고자 removeQueries를 이용하여, 같은 닉네임을 입력해도, 리스트에 표시가 되지 않게 개선하였습니다.

 

const queryClient = useQueryClient();
  const handleClickResult = useCallback(() => {
    if (userData) {
      if (contributors.findIndex((l) => l.userId === userData.userId) === -1) {
        setContributers([...contributors, userData]);
        queryClient.removeQueries([USER_API_KEY.USER, { q: inputValue }]);
      }
    }

    setInputValue('');
  }, [userData]);

 

완성 화면