[리팩토링]_각종 커스텀 훅을 통해서 관심사 분리하기

hanseungjune·2023년 7월 27일

리팩토링

목록 보기
3/25
post-thumbnail

관심사 분리를 하는 이유는?

코드의 복잡성을 낮추고, 유지보수를 위해서 한다. 여러 함수형태로 하는 것이 있지만, 리액트이기 때문에 커스텀 훅을 만들어서 해야겠다는 생각이 들었다. 그래서 시도하였고, 나름 커스텀 훅을 만드는 것에 대한 위화감을 없애고, 어쩌면 당연하게 생각하게 되기도 했다. 나름 좋은 계기였다.

작성 코드 및 설명

useAudio.js

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setAudio, setPlaying } from "../redux/actions/audioActions";

const useAudio = (url) => {
  const audio = useSelector((state) => state.audio.audio);
  const playing = useSelector((state) => state.audio.playing);
  const dispatch = useDispatch();

  const toggle = () => dispatch(setPlaying(!playing));

  const stop = () => {
    if (audio) {
      audio.pause();
      audio.currentTime = 0;
      dispatch(setPlaying(false));
    }
  };

  useEffect(() => {
    if (playing && audio) {
      audio.currentTime = 0;
      audio.play();
    } else if (!playing && audio) {
      audio.pause();
      dispatch(setPlaying(false));
    }
  }, [playing, audio]);

  useEffect(() => {
    if (audio) {
      audio.addEventListener("ended", () => dispatch(setPlaying(false)));
      return () => {
        audio.removeEventListener("ended", () => dispatch(setPlaying(false)));
      };
    }
  }, [audio, dispatch]);

  useEffect(() => {
    const newAudio = new Audio(url);
    dispatch(setAudio(newAudio));
    dispatch(setPlaying(false));
  }, [url, dispatch]);

  return [playing, toggle, stop];
};

export default useAudio;

이 커스텀 훅은 오디오 재생에 필요한 로직을 제공합니다. Redux의 useDispatch와 useSelector를 사용하여 오디오 상태를 관리하며, 오디오를 재생/일시정지하는 toggle 함수와 오디오를 멈추는 stop 함수를 제공합니다. 또한, 오디오 재생 상태나 URL이 변경될 때 오디오 재생 상태를 적절히 업데이트하는 useEffect를 사용합니다.

useAudioCall.js

import { useEffect } from "react";
import { useLocation, useNavigate, useParams } from "react-router-dom";
import useAudio from "../hooks/useAudio";

const useAudioCall = (url) => {
  const { id } = useParams();
  const navigate = useNavigate();
  const location = useLocation();

  const [playing, toggle, stop] = useAudio(url);

  useEffect(() => {
    let myTimer = setTimeout(() => {
      navigate(`/kiosk/${id}`);
    }, 500000);
    return () => {
      clearTimeout(myTimer);
    };
  }, [id, navigate]);

  return [id, navigate, location, playing, toggle, stop];
};

export default useAudioCall;

이 커스텀 훅은 useAudio 훅을 사용하여 오디오 재생을 관리하고, 특정 시간 후에 다른 페이지로 이동하는 로직을 제공합니다. useParams, useNavigate, useLocation을 사용하여 라우팅 관련 로직을 처리합니다.

useGetVideo.js

/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect } from "react";

const useGetVideo = (videoRef) => {
    const getVideo = () => {
        navigator.mediaDevices
          .getUserMedia({
            video: true,
          })
          .then((stream) => {
            let video = videoRef.current;
            if (video.paused) {
              video.srcObject = stream;
              video.play();
            }
          })
          .catch((err) => {
            console.error(err);
          });
      };
    
      useEffect(() => {
        getVideo();
      }, [videoRef, getVideo]);
}

export default useGetVideo

이 커스텀 훅은 비디오 스트림을 가져오는 로직을 제공합니다. navigator.mediaDevices.getUserMedia를 사용하여 비디오 스트림을 가져오고, 비디오 요소에 스트림을 연결합니다. useEffect를 사용하여 초기에 비디오 스트림을 가져오는 로직을 실행합니다.

useInterval.js

import { useEffect, useRef } from "react";

const useInterval = (callback, delay) => {
  const savedCallback = useRef();

  useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  useEffect(() => {
    function tick() {
      savedCallback.current();
    }
    if (delay !== null) {
      let id = setInterval(tick, delay);
      return () => clearInterval(id);
    }
  }, [delay]);
};

export default useInterval;

이 커스텀 훅은 특정 콜백을 주기적으로 실행하는 로직을 제공합니다. 콜백과 딜레이를 인자로 받아, 딜레이마다 콜백을 실행합니다. useEffect와 useRef를 사용하여 이 로직을 구현합니다.

이러한 커스텀 훅들은 코드를 더 깔끔하게 유지하는 데 도움이 됩니다. 같은 로직을 여러 곳에서 사용해야 할 때 커스텀 훅을 만들어 사용하면 코드의 중복을 줄이고 가독성을 높일 수 있습니다. 또한 로직을 더 잘 이해할 수 있도록 돕고, 테스트와 유지보수를 용이하게 합니다.

profile
필요하다면 공부하는 개발자, 한승준

0개의 댓글