React) 비디오 플레이어 뿌시기 (react-player)

숩딩·2023년 4월 13일
6

react-player 알아보기

React-Player 공식문서
https://www.npmjs.com/package/react-player

React 에서 플레이어를 사용하는 다양한 방법이 있는데 그 중 React-Player이 가장 많이 쓰인다.

React Player는 TypeScript와 함께 사용할 때 더 적합하다. 타입 정의 파일을 제공하며, TypeScript의 강력한 타입 검사기능을 활용하여 코드를 더 안전하고 유지 보수하기 쉽게 작성할 수 있게 해준다.

구현 과정

React Player

ReactPlayer을 먼저 설치하고

yarn add react-player

ReactPlayer 을 import 해서 사용하면 된다.

import ReactPlayer from 'react-player'

// Render a YouTube video player
<ReactPlayer url="https://www.youtube.com/watch?v=pSUydWEqKwE" />

url 은 비디오나 오디오의 url 을 입력해주면 된다.

next.js로 작업한다면 Hydration Error 이 뜰 것이다.

Hydration

이 Error을 해결하기 위해서는 SSR과 CSR 에 대한 이해가 필요하다.
CSR은 초기 로딩 속도 저하, SEO한계, 느린 인터넷 속도에서 유저가 빈 화면만 보게 되는 문제가 있고, SSR은 느린 페이지 전환과 서버 부하가 많다는 문제가 있다. 이런 한계점을 개선하기 위해 등장한게 SSR with Hydration 기법이다.

Hydration은 첫 페이지를 SSR방식으로 바고 이후 페이지에서는 CSR로 이뤄진다. hydration은 수분 보충이라는 뜻을 가지고 있는데 메말라있는 정적인 HTML(SSR)에 Hydration(수분보충)을 하여 동적기능(CSR)로 사용하는 것이라고 이해하면 된다.

이벤트 리스너 등록작업을 Hydrate라고 하는데 이런 작업을 개발자가 신경쓰지 않도록 하는 프레임워크가 Next.js 이다.

Next.js 에서는 첫 페이지를 SSR로 HTML을 전송 -> 브라우저에서 JS를 다운받고 React를 실행 -> 다른 페이지 이동시 CSR 하는 방식을 제공한다.

이 이미지를 참고해 서버와 클라이언트의 스펙트럼을 볼 수 있다.

Hydration error

위에서 발생한 hydration error이 일어나는 이유를 정리해보자면,

hydration error는 서버 측에서 생성된 HTML과 클라이언트 측에서 생성된 HTML이 다른 경우 발생 -> Next.js에서 페이지가 서버 측에서 생성되고 클라이언트 측에서 hydration되기 때문에 이 문제가 발생하는 것
그리고 React Player은 렌더링 시에 동적으로 생성되는 DOM 엘리먼트가 있음. 이런 동적 DOM 엘리먼트는 서버 측에서 생성되지 않으며, 클라이언트 측에서 생성됨. 따라서 React Player를 사용하면 서버 측에서 생성된 HTML과 클라이언트 측에서 생성된 HTML이 다르게 되어 hydration error가 발생하는 것!

나의 해결법은 useEffect 를 사용하여 컴포넌트가 마운트 된 이후에 렌더링 되는 방법을 사용했다.

import { useEffect, useState } from "react";
import ReactPlayer from "react-player";

export const MainPage = () => {
  const [isWindow, setIsWindow] = useState<boolean>(false);

  useEffect(() => {
    setIsWindow(true);
  }, []);

  return (
    <>
      <section>
        <h2>React Player</h2>
        {isWindow && (
          <div>
            <ReactPlayer url="https://www.youtube.com/watch?v=pSUydWEqKwE" />
          </div>
        )}
      </section>
    </>
  );
};

다른 방법이 있는지 chatGPT에 검색해보니

이러한 문제를 해결하기 위해서는, Next.js에서 React Player를 사용할 때 다음과 같은 방법을 고려할 수 있습니다.

  • dynamic import 사용:
    React Player를 동적으로 import하여 클라이언트 측에서 렌더링되도록 할 수 있습니다.
  • no-ssr 컴포넌트 사용:
    react-no-ssr 라이브러리를 사용하여 React Player를 서버 측에서 렌더링하지 않도록 할 수 있습니다.
  • useEffect를 이용한 지연 렌더링:
    React Player를 useEffect를 사용하여 컴포넌트가 마운트된 이후에 렌더링되도록 지연시킬 수 있습니다.

이러한 방법도 있다는 것 ~

props

Hydration Error을 해결했으니 마저 구현해보자잇

보통 사이트에 들어가서 비디오 플레이어를 사용할 때
sound 가 mute 되어 있는 것과 control할 수 있는 버튼들을 볼 수 있다.
그리고 autoPlay 되는 아이들도 있는데 이 모든것을 ReactPlayer로 조작이 가능하다.

[자주쓰이는 props]

  • url : 재생할 비디오 혹은 오디오의 URL
  • playing : 페이지 진입시 재생되도록 설정이 가능.기본값은 false이기 때문에 useState를 통해 조절해줄 것
  • controls : 플레이어의 기본 컨트롤러. 컨트롤러가 있어야 (자막, 화질, 속도 조절, 화면 비율 등 조절 가능) 유저가 동영상을 자신에게 맞는 방식으로 시청할 수 있기에 필요
  • muted: 플레이어 음소거 - 바로 재생이 될 경우 유저가 놀랄 수 있기 때문에 음소거를 넣는게 좋다고 생각하여 true로 해줄 것
  • 더 많은 프롭스는 공식문서 참고
import { useEffect, useState } from "react";
import ReactPlayer from "react-player";
import { Button } from "antd";
import styles from "./MainPage.module.css";

export const MainPage = () => {
  const [isWindow, setIsWindow] = useState<boolean>(false);
  const [isPlaying, setIsPlaying] = useState<boolean>(false);

  useEffect(() => {
    setIsWindow(true);
  }, []);

  const handleBtn = (): void => {
    setIsPlaying(!isPlaying);
  };

  return (
    <>
      <section>
        <h2>React Player</h2>
        <Button type="primary" onClick={handleBtn} style={{ marginBottom: 20 }}>
          플레이
        </Button>
        {isWindow && (
          <div className={styles.wrapper}>
            <ReactPlayer
              url="https://www.youtube.com/watch?v=pSUydWEqKwE"
              muted
              controls
              playing={isPlaying}
              width={"100%"}
              height={"100%"}
              className={styles.player}
            />
          </div>
        )}
      </section>
    </>
  );
};

'플레이' 버튼을 클릭했을 때 play가 되도록 구현하였다.
(control에 있는 재생 버튼을 클릭해도 플레이가 되는데 왜 플레이 버튼을 만들었냐면,나중에 특정 버튼 클릭시 원하는 구간 재생 같은 기능을 넣어줄 수 있기 때문에 playing={isPlaying} 따로 state 로 관리)

반응형으로 디스플레이 하기 위해 별도의 스타일을 넣음
https://stackoverflow.com/questions/49393838/how-to-make-reactplayer-scale-with-height-and-width

다음 포스팅에서 callback props를 사용하여 더 고도화 된 기능을 구현해 봐야겠다.

리액트 플레이어 데모 페이지인데 꽤나 유용하니까 사용해보시길!
https://cookpete.com/react-player/

번외

Reactjs-Media

Reactjs-Media는 비디오 및 오디오 재생을 위한 React 구성 요소를 제공한다.
이 라이브러리는 비디오 및 오디오 재생에 필요한 다양한 기능을 제공하지만, 특정 플랫폼에서의 동영상 및 오디오 재생은 지원하지 않는다.

Reactjs-media 가 궁금해져서
관련 블로그 글
을 보고 따라해보려 하였으나 Reactjs-Media는 type을 지정해주지 않는다. 그래서
이 오류가 발생했을 때 별도의 모듈파일을 생성하여 타입을 작성해줄 수 있지만 이렇게 작성해줘도 다른 곳에서 오류가 터졌다 ..
찾아보니 Reactjs-media는 파일 형식을 자동으로 감지해서 TypeScript에서 사용할 때 일부 유형 검사 오류가 발생하는 것인데 이러한 오류는 any 타입을 사용하여 해결할 수 있지만, TypeScript의 강력한 타입 검사기능을 포기하는 것이기 때문에 권장되는 방법은 아님..

더 다양한 플레이어 라이브러리들을 보고싶다면 이 블로그를 참고하면 좋을 것 같다.

참고 :
Typescript를 지원하지 않는 NPM Module, NPM Module 타입 선언 파일(.d.ts)을 커스텀 대체하기 (https://samsons.tistory.com/47)

profile
Front-End Developer ✨