Skip to content

React‐Query와 Socket과 함께 춤을

nowChae edited this page Dec 3, 2024 · 1 revision

Socker Server State 관리 전략

현재 프로젝트는 실시간 양방향 통신을 위해 소켓을 활용하고 있으며, 대부분의 데이터가 소켓을 통해 주고받는 형태다. 기존에는 API를 통해 서버 데이터를 수신하고 이를 React-Query로 관리하려 했으나, API 호출이 적어 소켓 기반 데이터 관리로 방향을 전환했다. 따라서 소켓 통신으로 받는 Server State를 React-Query로 브라우저 캐시에서 관리하는 방안을 고민하게 되었다.

브라우저 캐시에 저장할 데이터의 기준

소켓을 통해 전달되는 모든 데이터를 브라우저 캐시에 저장하는 것은 비효율적이다. 예를 들어, 채팅과 같은 자주 변동되는 데이터는 캐시할 필요가 없다. 반면, 퀴즈 상태, 참가자 정보와 같은 준영속적이고 중요한 데이터는 캐시 관리에 포함하는 것이 바람직하다

React-Query와 Socket의 효율적 통합: useSuspenseQueryemitEventWithAck 활용

소켓 데이터를 관리할 때 React-QueryuseSuspenseQuery를 결합하면, 소켓 기반 데이터 흐름에서도 브라우저 캐시와 상태 관리를 효율적으로 수행할 수 있다. 기존의 useState 대신 React-Query의 캐시를 활용하여, 새로고침 시 자동으로 데이터를 패치할 수 있는 구조를 제공한다. 이를 위해emitEventWithAck 함수를 사용하여 소켓 이벤트를 Promise 기반으로 처리한다.

emitEventWithAck: 소켓 이벤트의 Promise 래핑

import { Socket } from 'socket.io-client';

export const emitEventWithAck = <T>(socket: Socket, event: string, data: any) => {
  return new Promise<T>((resolve, reject) => {
    socket.emit(event, data, (response: T) => {
      if (response) {
        resolve(response);
      } else {
        reject(new Error(`"${event}" event emit failed`));
      }
    });
  });
};

useQuizSession: React-Query와 소켓 데이터 통합

이 훅은 useSuspenseQuery를 사용하여 소켓 데이터를 React-Query의 캐시에서 관리한다. 이를 통해 퀴즈 세션 데이터를 브라우저에서 자동으로 캐싱하며, 새로고침 시에도 데이터를 자동으로 불러올 수 있는 구조를 제공한다.

//예시 코드
export const useQuizSession = ({ socket, pinCode }: UseQuizSessionProps) => {
  return useSuspenseQuery({
    queryKey: ['show quiz', pinCode],
    queryFn: () => emitEventWithAck<ShowQuizResponse>(socket, 'show quiz', { pinCode }),
  });
};

사용 사례 및 장점

  • useState 불필요: 소켓 데이터를 관리하는 데 useState 대신 React-Query의 캐시를 사용하여 코드가 간결해진다.
  • 자동 새로고침: 새로고침 시에도 useSuspenseQuery가 자동으로 데이터를 패치해 최신 상태를 유지할 수 있다.
  • 응답 대기 처리: emitEventWithAck를 통해 소켓 이벤트 응답을 Promise로 관리하여 비동기 처리와 에러 핸들링이 용이하다.
  • 효율적인 캐시 관리: React-Query의 queryKey를 활용해 필요한 데이터만 갱신하고 불필요한 요청을 줄인다.
Clone this wiki locally