React-Query (with WebSocket)

Thomas·2022년 7월 22일
1
post-thumbnail

Overview

Tech day 에서 “React-Query 를 활용할 때, WebSocket 을 통해서 부분 데이터가 넘어왔을 경우, 변경된 서버 데이터를 모두 refetch 해야 할까?” 라는 질문에 대한 조사를 하라는 숙제를 받았습니다.

React-Query 로 관리되는 서버 데이터는 한 묶음입니다. 예를들어 현재 화면에 뿌려져있는 서버 데이터가 아래 데이터라고 봅시다.

{
  content: {
    id: 1,
    title: "hi!",
    content: "content"
  }
}

서버에서 title 값이 변경되어 title 값만 변경 되었다고 하면, 해당 데이터를 stale (유통기한이 지난) 한 데이터라고 판단해서 다시 fetching 해야 할까요?

{
  content: {
    id: 1,
    title: "hello!",
    content: "content"
  }
}

윗 질문에 대한 Best Case 가 있어서 가져와봤습니다. 해당 케이스는 React-Query 공식 홈페이지에 연결되어있는 공식 블로그에 나와있는 Case 이므로 Best Case 로 봐도 무방 하다고 생각합니다.

#1. queryClient.invalidateQueries 를 활용

첫 번째 케이스는, 해당 서버 데이터 (Server State) 가 stale 하다고 판단하고 리패칭을 하자 입니다.

해당 코드를 블로그에서 가져와봤습니다.

const useReactQuerySubscription = () => {
  const queryClient = useQueryClient()
  React.useEffect(() => {
    const websocket = new WebSocket('wss://echo.websocket.org/')
    websocket.onopen = () => {
      console.log('connected')
    }
    websocket.onmessage = (event) => {
      const data = JSON.parse(event.data)
      const queryKey = [...data.entity, data.id].filter(Boolean)
      queryClient.invalidateQueries(queryKey) // 메세지를 받았을 경우 리패칭
    }

    return () => {
      websocket.close()
    }
  }, [queryClient])
}

윗 코드를 살펴보면 웹소켓에서 메세지를 받았을 경우 invalidateQueries 를 활용해 해당하는 쿼리를 stale 하게 만들어 리패칭 합니다.

웹소켓을 통해서 데이터의 한 부분이 변경 되었으니, 현재 데이터는 최신 데이터임을 보장할 수 없고 변경된 모든 상태를 리패칭하자 라는 것입니다.

#2. queryclient.setQueriesData 를 활용

웹소켓을 통해서 데이터를 전달받았을 때 전달받은 데이터가 해당 컴포넌트에서 국한적으로 사용하는 데이터일 경우에 setQueriesData 를 통해서 데이터를 변경해줄 수 있습니다. React-Query 는 쿼리 한 데이터를 캐싱 합니다. setQueriesData 는 특정 키의 쿼리를 서버에서 리패칭해 변경하는 것이 아닌 캐싱 된 데이터의 데이터를 변경하는 메서드입니다.

const useReactQuerySubscription = () => {
  const queryClient = useQueryClient()
  React.useEffect(() => {
    const websocket = new WebSocket('wss://echo.websocket.org/')
    websocket.onopen = () => {
      console.log('connected')
    }
    websocket.onmessage = (event) => {
      const data = JSON.parse(event.data)
      queryClient.setQueriesData(QueryKey, (oldData) => oldData ? {id:data, ...oldData} : undefined);
    }
    return () => {
      websocket.close()
    }
  }, [queryClient])
}

위 코드를 살펴보면 setQueriesData 메서드에서 매개변수로 데이터를 변경할 쿼리 키와, 변경할 데이터를 리턴하는 함수를 인자로 넣어줬습니다.

웹소켓을 통해서 통신하는 쿼리가 해당 컴포넌트에서만 사용되며, 해당 쿼리의 전체 데이터를 서버와 통신한다면 통신을 통해 전달받은 데이터가 최신 데이터라고 가정하고 (싱크가 맞다고 가정) setQueriesData 를 활용하여 전달받은 데이터의 일부만 수정하는 방법입니다.

staleTime: infinity //default 0

이 방법을 활용하려면 query 옵션을 셋팅할 때 staleTime 을 넉넉하게 잡아줘야 합니다. 공식 블로그에서는 staleTimeinfinity 로 설정하였습니다. staleTimeinfinity 로 설정할 경우 쿼리의 유통기한 만료 시점이 정해지지 않으므로 리패칭 트리거가 발동하지 않는 한 stale 한 상태로 변경되지 않습니다.

참고 문헌
- 공식 문서 (setQueriesData)
- 공식 블로그

profile
안녕하세요! 주니어 웹 개발자입니다 😆

0개의 댓글