1.x에서 마이그레이션
이 문서는 react-native-youtube-bridge 1.x에서 2.x로 이동하는 방법을 설명합니다.
2.x API는 expo-audio, expo-video 같은 현대적인 Expo API처럼 Hook 중심으로 다시 설계되었습니다.
변경 사항 개요
1. 컴포넌트 API 교체
이전 방식: 1.x
import { YoutubePlayer } from 'react-native-youtube-bridge';
<YoutubePlayer
ref={playerRef}
source="AbZH7XWDW_k"
height={400}
playerVars={{
autoplay: true,
controls: true,
playsinline: true,
rel: false,
muted: true,
}}
onReady={handleReady}
onStateChange={handleStateChange}
onProgress={handleProgress}
onError={handleError}
/>;
현재 방식: 2.x
import { YoutubeView, useYouTubePlayer } from 'react-native-youtube-bridge';
const player = useYouTubePlayer('AbZH7XWDW_k', {
autoplay: true,
controls: true,
playsinline: true,
rel: false,
muted: true,
});
<YoutubeView player={player} height={400} />;
2. 플레이어 설정을 useYouTubePlayer로 이동
1.x에서는 대부분의 플레이어 옵션을 컴포넌트의 playerVars로 전달했습니다.
<YoutubePlayer
source="AbZH7XWDW_k"
playerVars={{
autoplay: true,
controls: true,
muted: true,
}}
/>
2.x에서는 같은 옵션을 useYouTubePlayer의 두 번째 인자로 전달합니다.
const player = useYouTubePlayer('AbZH7XWDW_k', {
autoplay: true,
controls: true,
muted: true,
});
<YoutubeView player={player} />;
height, width, style, iframeStyle, webViewStyle, webViewProps, useInlineHtml, webViewUrl 같은 렌더링 관련 prop은 YoutubeView에 남겨둡니다.
3. 이벤트를 useYouTubeEvent로 이동
useYouTubeEvent는 state-style 구독과 callback-style side effect를 모두 지원합니다.
이전 방식: 1.x callback props
const [isPlaying, setIsPlaying] = useState(false);
const [currentTime, setCurrentTime] = useState(0);
const [duration, setDuration] = useState(0);
const [playbackRate, setPlaybackRate] = useState(1);
const [availableRates, setAvailableRates] = useState([1]);
const handleReady = useCallback((playerInfo) => {
if (playerInfo?.availablePlaybackRates) {
setAvailableRates(playerInfo.availablePlaybackRates);
}
}, []);
const handleStateChange = useCallback((state) => {
setIsPlaying(state === PlayerState.PLAYING);
}, []);
const handleProgress = useCallback((progress) => {
setCurrentTime(progress.currentTime);
setDuration(progress.duration);
}, []);
<YoutubePlayer
source="AbZH7XWDW_k"
onReady={handleReady}
onStateChange={handleStateChange}
onProgress={handleProgress}
/>;
현재 방식: 2.x event hook
const player = useYouTubePlayer('AbZH7XWDW_k');
// State-style 구독
const playbackRate = useYouTubeEvent(player, 'playbackRateChange', 1);
const progress = useYouTubeEvent(player, 'progress', 1000);
const state = useYouTubeEvent(player, 'stateChange');
const currentTime = progress?.currentTime ?? 0;
const duration = progress?.duration ?? 0;
const isPlaying = state === PlayerState.PLAYING;
// Callback-style side effect
const [availableRates, setAvailableRates] = useState([1]);
useYouTubeEvent(player, 'ready', (playerInfo) => {
if (playerInfo.availablePlaybackRates) {
setAvailableRates(playerInfo.availablePlaybackRates);
}
});
useYouTubeEvent(player, 'autoplayBlocked', () => {
console.log('Autoplay was blocked');
});
useYouTubeEvent(player, 'error', (error) => {
console.error('Player error:', error);
});
return <YoutubeView player={player} />;
4. ref 기반 제어를 직접 메서드 호출로 교체
이전 방식: 1.x ref methods
const playerRef = useRef<PlayerControls>(null);
const play = () => playerRef.current?.play();
const pause = () => playerRef.current?.pause();
const stop = () => playerRef.current?.stop();
const seekTo = (time: number) => playerRef.current?.seekTo(time, true);
const setVolume = (volume: number) => playerRef.current?.setVolume(volume);
const mute = () => playerRef.current?.mute();
const unMute = () => playerRef.current?.unMute();
const getPlayerInfo = async () => {
const currentTime = await playerRef.current?.getCurrentTime();
const duration = await playerRef.current?.getDuration();
const state = await playerRef.current?.getPlayerState();
};
<YoutubePlayer ref={playerRef} source="AbZH7XWDW_k" />;
현재 방식: 2.x direct player methods
const player = useYouTubePlayer('AbZH7XWDW_k');
const play = () => player.play();
const pause = () => player.pause();
const stop = () => player.stop();
const seekTo = (time: number) => player.seekTo(time, true);
const setVolume = (volume: number) => player.setVolume(volume);
const mute = () => player.mute();
const unMute = () => player.unMute();
const getPlayerInfo = async () => {
const currentTime = await player.getCurrentTime();
const duration = await player.getDuration();
const state = await player.getPlayerState();
};
<YoutubeView player={player} />;
비동기 getter 값을 안정적으로 사용해야 한다면 ready 이벤트 이후에 호출하세요. YoutubeView가 내부 controller를 연결하기 전에는 getter가 undefined를 반환할 수 있습니다.
5. source 처리 방식 업데이트
두 버전 모두 비디오 ID와 YouTube URL을 지원하지만, 2.x에서는 source를 YoutubePlayer가 아니라 useYouTubePlayer에 전달합니다.
const playerA = useYouTubePlayer('AbZH7XWDW_k');
const playerB = useYouTubePlayer({ videoId: 'AbZH7XWDW_k' });
const playerC = useYouTubePlayer({ url: 'https://youtube.com/watch?v=AbZH7XWDW_k' });
6. 렌더링 모드 마이그레이션
렌더링 모드 관련 prop은 렌더 표면에 속하므로 YoutubeView로 이동합니다.
이전 방식: 1.x
<YoutubePlayer
source="AbZH7XWDW_k"
useInlineHtml={false}
webViewUrl="https://your-custom-player.com"
/>
현재 방식: 2.x
const player = useYouTubePlayer('AbZH7XWDW_k');
<YoutubeView player={player} useInlineHtml={false} webViewUrl="https://your-custom-player.com" />;
마이그레이션 체크리스트
필수 변경
선택 개선
Breaking changes 요약
YoutubePlayer가 useYouTubePlayer + YoutubeView로 대체되었습니다.
- 이벤트 prop은 제거되고
useYouTubeEvent를 사용합니다.
- ref 기반 제어는 직접 player method 호출로 바뀌었습니다.
playerVars는 컴포넌트 prop에서 hook config로 이동했습니다.
- 직접 관리하던 상태는 reactive event 값으로 대체할 수 있습니다.
대부분의 앱은 화면 단위로 천천히 마이그레이션할 수 있습니다. 먼저 useYouTubePlayer로 player를 만들고 YoutubeView로 렌더링한 뒤, 이벤트와 ref 호출을 hook/direct method 방식으로 옮기면 됩니다.