Tikitaza 리팩토링 1 - useSse

김영현·2024년 3월 24일
0

tikitaza 리팩토링기

목록 보기
1/1

Tikitaza

프로그래머스 프론트엔드 데브코스 5기에서 마지막으로 진행한 프로젝트!
마지막 프로젝트답게 8주라는 기간과 BE분들과의 협업을 통해 이루어졌다.

당장 엊그제인 2024.03.22(금)이 제출마감기한이었고 이미 제출은 끝났다.

하지만 아쉬운점이 남아있기도 하고 다른 팀원분들도 리팩토링 의사가 있으셔서 나 또한 맡은 부분을 꼭 리팩토링 하고싶었다.
이번 주말을 활용해 리팩토링을 진행해 보았다.


useSSE

처음 만들었던 useSSE라는 훅은 이름 답게 Server-sent-event를 활용하는 훅이다.
다만 굉장히 한정적인 상황에서만 쓸 수 있었다.

기존 useSSE

const useSSE = ({ url, options = {} }: UseSSEProps) => {
  const [error, setError] = useState<SSEErrorType>(null);
  const [data, setData] = useState<I_ChangeGameRoomData[]>([]);

  const isError = useMemo(() => !!error, [error]);
  const memorizedOptions = useRef(options);

  useEffect(() => {
    const sse = new EventSourcePolyfill(url, { ...memorizedOptions.current });

    const handleChangeGameRoom = (e: Event) => {
      const messageEvent = e as MessageEvent;
      const data = JSON.parse(messageEvent.data);
      setData(data);
    };

    const handleInitConnect = (e: Event) => {
      const messageEvent = e as MessageEvent;
      const data = JSON.parse(messageEvent.data);

      setData(data);
    };

    sse.onopen = () => {
      setError(null);

      sse.addEventListener(SSE_CHANGE_GAME_ROOM, handleChangeGameRoom);
      sse.addEventListener(SSE_CONNECT, handleInitConnect);
    };

    sse.onerror = (e: Event) => {
      setError(e);
    };

    return () => {
      sse.removeEventListener(SSE_CHANGE_GAME_ROOM, handleChangeGameRoom);
      sse.removeEventListener(SSE_CONNECT, handleInitConnect);
      sse.close();
    };
  }, [url, memorizedOptions]);

  return {
    data,
    isError,
    error,
  };
};

위 코드의 문제점은 무엇일까?

크게 생각나는건 다음과 같다.

  • 이름과 달리 내부에서 선언한 특정 이벤트만 수신한다. 만약 myEvent라는 이벤트 이름으로 데이터를 받고싶을땐, 새로 만들어야 한다.
  • 특정 이벤트만 수신하기에 받는 데이터도특정 데이터만 받는다.

문제점을 인지하였다. 그러면, 외부에서 이벤트이름을 주입받게 하고 데이터의 타입도 주입받게 하면 될 것 같다.

리팩토링 이후 useSse

interface UseSseProps<K> {
  url: string;
  customEvents?: K[];
  options?: EventSourcePolyfillInit;
}

const useSse = <K extends string, T = unknown>({
  url,
  customEvents,
  options = {},
}: UseSseProps<K>) => {
  const [isConnected, setIsConnected] = useState(false);
  const [data, setData] = useState<T>();
  const [error, setError] = useState<SseErrorType>(null);
  const isError = useMemo(() => !!error, [error]);
  const memorizedOptions = useRef(options);

  useEffect(() => {
    const eventSource = new EventSourcePolyfill(url, {
      ...memorizedOptions.current,
    });

    const handleCustomEventData = (e: Event) => {
      const messageEvent = e as MessageEvent;
      const data = JSON.parse(messageEvent.data);
      setData(data);
    };

    eventSource.onopen = () => {
      setError(null);
      setIsConnected(true);

      customEvents?.forEach((customEvent) =>
        eventSource.addEventListener(customEvent, handleCustomEventData)
      );
    };

    eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      setData(data);
    };

    eventSource.onerror = (e) => {
      setError(e);
      setIsConnected(false);
    };

    return () => {
      customEvents?.forEach((customEvents) =>
        eventSource.removeEventListener(customEvents, handleCustomEventData)
      );
      eventSource.close();
    };
  }, [url]);

  return { isConnected, data, error, isError };
};
  • 제네릭을 이용하여 커스텀 이벤트의 타입을 받아오고 커스텀 이벤트의 데이터 타입도 받아온다.
  • EventSourcePolifyll에 커스텀 이벤트 핸들러를 부착할땐 파라미터가 무조건 Event를 수신하게 되어있다. 따라서 as키워드로 강제 타입변환을 진행(라이브러리임)

이전과 크게 바뀌진 않았다. 다만 새로운 이벤트 네이밍새로운 데이터를 받을 수 있게 변화했다.

리팩토링 이후의 개선점?

잘 해결 된 것 같지만, 아직도 문제점이 남아있는 것 같다...!
이벤트 핸들러데이터만 저장한다. 특정 이벤트를 수신했을때 원하는 함수를 호출할 수 없다.

물론, 외부에서 이렇게 사용할수 도 있다.

const { data } = useSse<...>(...);

useEffect(() => {
  if(data.name === 'my'){
	...
  }
    //data는 보통 객체지만...편의상 이렇게 진행함.
}, [data])

이게 과연 맞는걸까?

하지만 개선한다고 외부에서 이벤트 핸들러를 부착하게 된다면, 인자로 받아오는 값이 꽤 많아질 것이다.

const { data } = useSse<...>({
  //아마 아래와 같이 받아야하지 않을까...?
  customEvents:[
     { eventName:'myEvent', handler: (e) => {...} },
     { ... }
  ]
});

아직 무엇이 맞는지는 모른다...🙃
개선점으로 적어두고 나중에 실력이 향상됐을때 보면, 또 다른 관점을 얻을 수 있지 않을까?


profile
모르는 것을 모른다고 하기

0개의 댓글