[react-query] useQuery의 데이터 불변성을 지켜야할까??

Ell!·2021년 11월 1일
0

react

목록 보기
5/28

Should I keep immutable in data, useQuery??

개요

이전에 유저별 등록 게임 모달을 만들면서 유저별로 등록한 게임을 다루면서 유저가 직접 게임의 우선순위를 부여할 수 있게 하기 위해서 react-beautiful-dnd 라이브러리를 사용해서 직접 조정할 수 있게 만들었었다.

서버와의 연결을 해서 유저가 등록한 게임을 []로 받아온 상황. 여기서 헷갈렸던 것이 useQuery를 통해 받아오는 data를 직접 수정해도 되는지였다. 오늘 작업을 하기 전부터 기대 반 걱정 반이었는데, 결론부터 말하자면 수정이 가능하다!! 하지만! 그렇게 하면 데이터의 불변성을 지킬 수 없다.

우선 불변성을 고려하지 않은 코딩이다. 이렇게해도 작동은 한다. 어떤 side effect가 생길지 몰라서 걱정되는 것 뿐...

data의 불변성을 지키지 않는 코드 설명

먼저 서버에서 필요한 데이터를 받아왔다.

const { data, isFetching, isLoading, isError } = useQuery(
    ['game-account-list'],
    async () => {
      const result = await axiosInstance.get('게임리스트api');
      console.log(result);
      return result;
    },
    {
      refetchOnWindowFocus: false,
      refetchOnMount: true,
      refetchOnReconnect: true,
      retry: 2,
      initialData: [],
      keepPreviousData: true,
    },
  );

여기서 받아온 데이터를 직접 dnd에서 수정했다.

const reorder = (list, startIdx, endIdx) => {
  const result = Array.from(list);
  const [removed] = result.splice(startIdx, 1);
  result.splice(endIdx, 0, removed);

  return result;
};

const Component = () => {

...
  
  /* 선택한 태그 드래그 앤 드롭 */
  // 드래그 끝나면 할 일
  const onDragEnd = result => {
    // source : 현재 위치한 droppable의 위치, 인덱스
    // destination : dnd를 마친 후 droppable의 위치, 인덱스

    // 바깥으로 drop 시에
    if (!result.destination) {
      return;
    }

    // 같은 자리에 가져다 두었다면 그냥 리턴
    if (result.destination.index === result.source.index) {
      return;
    }

    const items = reorder(
      data.data,
      result.source.index,
      result.destination.index,
    );

    if (data) data.data = items; // 새로운 것 옮겨두고.
    // 이렇게 data.data에다가 직접적으로 수정해주었다. 
  };

 ...
}

이 상태에서 수정한 data.data를 저장하는 버튼을 만들었다. 이건 react-query의 useMutation으로.

const gameListMutate = useMutation((items)=>{
	return axiosInstance.put('게임리스트api', items);
})

// 제출 시에 일어나는 logic
 const onGameEnrollmentOrderSubmit = () => {

    // mutate - 일단은 바로바로 저장됨. 저장버튼 눌러야 되는 걸로 변경??
    gameListMutate.mutate(data.data, {
      onSuccess: () => {
        closeModal();
        return queryClient.invalidateQueries(['game-account-list']); // 이전에도 적었다시피 return을 해주면 closeModal하고 일어난다!
      },
      onError: err => {
        console.log(err);
      },
    });
  };

data의 불변성은 왜 필요한가?

이와 관련된 논의가 react-query 라이브러리에서 있었다.

https://github.com/tannerlinsley/react-query/discussions/1304

만약 useQuery에서 받아온 data를 위와 같은 방법으로 직접 수정하면 어떻게 될까? 캐싱된 데이터에 영향을 끼치게 된다.

  • LOL, maple 순으로 들어있던 data

  • react-beautiful-dnd를 사용해서 드래그 앤 드랍했을 때, 캐싱된 데이터가 바뀐 것을 확인할 수 있다.

해결방법은??

https://github.com/tannerlinsley/react-query/discussions/530

받아온 data를 useMemo를 이용해서 새로운 변수에다가 집어넣으라는 답변이 있었다.

https://tkdodo.eu/blog/react-query-data-transformations

react-query의 contributor 중 한 명인 TkDodo 님의 블로그에도 이와 관련된 포스팅이 있었다.

react에서는 항상 데이터의 불변성을 유지해주어야 한다는 사실 잊지 말자!

참고

react-query, react-beautiful-dnd 라이브러리

profile
더 나은 서비스를 고민하는 프론트엔드 개발자.

0개의 댓글