음악 재생 슬라이더

dongmin·2024년 6월 2일
2

Trouble Shooting

목록 보기
4/6
post-thumbnail
post-custom-banner

요구사항

  • 음악 재생시간에 따라서 슬라이더가 업데이트
  • 슬라이더를 드래그하여 원하는 재생시간으로 이동
  • 음악재생 중에 슬라이더를 드래그하면 음악의 현재시간이 아닌 드래그 위치를 따라오도록 함

문제 1

슬라이더 밖에서 드래그를 끝내면 음악을 재생해도 슬라이더가 움직이지 않음

원인

<Slider
	aria-label="Volume"
	value={currentTime}
	onChange={handleSliderChange}
	onChangeCommitted={handleSliderRelease}
	onMouseDown={() => setIsDragging(true)} // 슬라이더를 드래그하기 시작하면 상태를 변경합니다.
	onMouseUp={() => setIsDragging(false)} // 슬라이더에서 손을 떼면 상태를 변경합니다.
	size="medium"
	color="secondary"
	max={musicData.duration}
 />

위와 같이 음악 재생 슬라이더를 onMouseDownonMouseUp 옵션을 사용하여 현재 드래그 상태에 대한 여부를 상태로 관리하였는데 해당 옵션은 슬라이더 내부 영역에서만 마우스 상태를 인식하기 때문에 드래그를 하면서 슬라이더 밖으로 마우스가 나가게 되면 setIsDragging(false) 이 실행되지 않는다.

드래그상태는 슬라이더를 드래그하는 동안 슬라이더가 음악의 현재시간에 따라서 업데이트 되지 않도록 하기 위함이다.

해결

<Slider
	className="time-slider"
	aria-label="Volume"
	value={currentTime}
	onChange={handleSliderChange}
	onChangeCommitted={handleSliderRelease}
  	onMouseDown={() => setIsDragging(true)}
	size="medium"
	color="secondary"
	max={musicData.duration}
/>

슬라이더의 onMouseUp 옵션을 제거

useEffect(() => {
    // 마우스 업 이벤트를 전역적으로 처리
    const handleMouseUpGlobal = () => {
      setIsDragging(false); // 드래그 상태 업데이트
    };

    window.addEventListener('mouseup', handleMouseUpGlobal); // 전역에 마우스 업 이벤트 추가

    return () => {
      // 클린업 함수에서 이벤트 리스너 제거
      window.removeEventListener('mouseup', handleMouseUpGlobal);
    };
  }, []);

mouseup 이벤트를 전역적으로 처리하도록 코드 추가하여 슬라이더 밖에서 mouseup 되어도 드래그 상태가 업데이트되어 문제가 해결되었다.

새롭게 알게된 점

MUI Slider 컴포넌트의 onMouseUp , onMouseDown 옵션은 해당 컴포넌트 영역 내부의 마우스 이벤트만 인식할 수 있다. 이러한 제한은 전역적으로 마우스 이벤트를 추가하여 해결할 수 있다.

문제 2

음악페이지에 처음 접근했을 때 음악을 재생하면 음악은 정상적으로 나오지만 재생 슬라이더가 움직이지 않음

원인

useEffect(() => {
    const audioElement = audioRef.current;

    if (audioElement) {
      const handleTimeUpdate = () => {
        // 슬라이더를 드래그 중이 아닐 때만 현재 재생 시간을 설정합니다.
        if (!isDragging) {
          setCurrentTime(audioElement.currentTime);
        }
      };
      audioElement.addEventListener('timeupdate', handleTimeUpdate);
      return () => {
        audioElement.removeEventListener('timeupdate', handleTimeUpdate);
      };
    }
  }, [audioRef, isDragging]);

audio 컴포넌트가 마운트 되면 audioRef 값이 업데이트 되는 줄 알고 audioRef 를 종속성 배열에 포함시켰지만 로그를 찍어 확인해보면 audioElement 값은 null 로 출력되었다.

해결

useEffect(() => {
    const audioElement = audioRef.current;

    if (audioElement) {
      const handleTimeUpdate = () => {
        // 슬라이더를 드래그 중이 아닐 때만 현재 재생 시간을 설정합니다.
        if (!isDragging) {
          setCurrentTime(audioElement.currentTime);
        }
      };
      audioElement.addEventListener('timeupdate', handleTimeUpdate);
      return () => {
        audioElement.removeEventListener('timeupdate', handleTimeUpdate);
      };
    }
  }, [audioRef.current, isDragging]);

audioRef 를 종속성 배열에 넣으면, 참조 객체의 변화를 감지하는 것이 아니라 참조 자체를 나타내기 때문에 참조가 처음 생성될 때 한 번만 useEffect 가 실행된다.

하지만 audioRef.current 를 배열에 넣게 되면, 참조가 실제로 가리키는 값, 즉 오디오 엘리먼트가 실제로 DOM에 마운트되는 순간을 감지할 수 있게되어 audioElement 값이 null 이 아닌 실제 값으로 업데이트된다.

새롭게 알게된 점

useRef 로 생성된 audioRef 객체는 참조 자체를 나타낸다.
때문에 컴포넌트의 생명주기 동안 안정적이고 변경되지 않아서 useEffect의 종속성 배열에 넣으면 useEffect 는 한 번만 실행된다.

audioRef.current 는 참조가 현재 가리키고 있는 값이다.
이 값은 오디오 엘리먼트 자체를 가리키며, 컴포넌트가 렌더링되면서 오디오 엘리먼트가 DOM에 연결될 때 설정된다. 만약 오디오 컴포넌트가 처음 마운트될 때 null에서 실제 DOM 엘리먼트로 변경된다면, audioRef.current 값은 null 에서 참조가 가리키고 있는 엘리먼트 값으로 변하게 된다.

profile
아이스박스
post-custom-banner

0개의 댓글