1+ import { EventEmitter } from 'events' ;
12import React , {
2- useRef ,
3- useState ,
4- useEffect ,
53 forwardRef ,
64 useCallback ,
5+ useEffect ,
76 useImperativeHandle ,
87 useMemo ,
8+ useRef ,
9+ useState ,
910} from 'react' ;
10- import { View , StyleSheet , Platform } from 'react-native' ;
11- import { WebView } from './WebView' ;
11+ import { Platform , StyleSheet , View } from 'react-native' ;
1212import {
13+ CUSTOM_USER_AGENT ,
14+ DEFAULT_BASE_URL ,
1315 PLAYER_ERROR ,
1416 PLAYER_STATES ,
15- DEFAULT_BASE_URL ,
16- CUSTOM_USER_AGENT ,
1717} from './constants' ;
18- import { EventEmitter } from 'events' ;
1918import {
20- playMode ,
21- soundMode ,
2219 MAIN_SCRIPT ,
2320 PLAYER_FUNCTIONS ,
21+ playMode ,
22+ soundMode ,
2423} from './PlayerScripts' ;
24+ import { WebView } from './WebView' ;
25+
26+ const deepComparePlayList = ( lastPlayList , playList ) => {
27+ return (
28+ typeof lastPlayList === typeof playList &&
29+ ( Array . isArray ( lastPlayList )
30+ ? lastPlayList . join ( '' )
31+ : lastPlayList === Array . isArray ( playList )
32+ ? playList . join ( '' )
33+ : playList )
34+ ) ;
35+ } ;
2536
2637const YoutubeIframe = ( props , ref ) => {
2738 const {
@@ -41,7 +52,7 @@ const YoutubeIframe = (props, ref) => {
4152 onError = _err => { } ,
4253 onReady = _event => { } ,
4354 playListStartIndex = 0 ,
44- initialPlayerParams = { } ,
55+ initialPlayerParams,
4556 allowWebViewZoom = false ,
4657 forceAndroidAutoplay = false ,
4758 onChangeState = _event => { } ,
@@ -50,6 +61,10 @@ const YoutubeIframe = (props, ref) => {
5061 onPlaybackRateChange = _playbackRate => { } ,
5162 } = props ;
5263
64+ const lastVideoIdRef = useRef ( videoId ) ;
65+ const lastPlayListRef = useRef ( playList ) ;
66+ const initialPlayerParamsRef = useRef ( initialPlayerParams || { } ) ;
67+
5368 const webViewRef = useRef ( null ) ;
5469 const eventEmitter = useRef ( new EventEmitter ( ) ) ;
5570 const [ playerReady , setPlayerReady ] = useState ( 0 ) ;
@@ -126,6 +141,39 @@ const YoutubeIframe = (props, ref) => {
126141 ] . forEach ( webViewRef . current . injectJavaScript ) ;
127142 } , [ play , playerReady , mute , volume , playbackRate ] ) ;
128143
144+ useEffect ( ( ) => {
145+ if ( playerReady < 1 || lastVideoIdRef . current === videoId ) {
146+ // no instance of player is ready
147+ // or videoId has not changed
148+ return ;
149+ }
150+
151+ lastVideoIdRef . current = videoId ;
152+
153+ webViewRef . current . injectJavaScript (
154+ PLAYER_FUNCTIONS . loadVideoById ( videoId , play ) ,
155+ ) ;
156+ } , [ videoId , play , playerReady ] ) ;
157+
158+ useEffect ( ( ) => {
159+ if ( playerReady < 1 ) {
160+ // no instance of player is ready
161+ return ;
162+ }
163+
164+ // Also, right now, we are helping users by doing "deep" comparisons of playList prop,
165+ // but in the next major we should leave the responsibility to user (either via useMemo or moving the array outside)
166+ if ( ! playList || deepComparePlayList ( lastPlayListRef . current , playList ) ) {
167+ return ;
168+ }
169+
170+ lastPlayListRef . current = playList ;
171+
172+ webViewRef . current . injectJavaScript (
173+ PLAYER_FUNCTIONS . loadPlaylist ( playList , playListStartIndex , play ) ,
174+ ) ;
175+ } , [ playList , play , playListStartIndex , playerReady ] ) ;
176+
129177 const onWebMessage = useCallback (
130178 event => {
131179 try {
@@ -141,15 +189,6 @@ const YoutubeIframe = (props, ref) => {
141189 case 'playerReady' :
142190 onReady ( ) ;
143191 setPlayerReady ( prev => prev + 1 ) ;
144- if ( Array . isArray ( playList ) ) {
145- webViewRef . current . injectJavaScript (
146- PLAYER_FUNCTIONS . loadPlaylist (
147- playList ,
148- playListStartIndex ,
149- play ,
150- ) ,
151- ) ;
152- }
153192 break ;
154193 case 'playerQualityChange' :
155194 onPlaybackQualityChange ( message . data ) ;
@@ -169,13 +208,10 @@ const YoutubeIframe = (props, ref) => {
169208 }
170209 } ,
171210 [
172- play ,
173211 onReady ,
174212 onError ,
175- playList ,
176213 onChangeState ,
177214 onFullScreenChange ,
178- playListStartIndex ,
179215 onPlaybackRateChange ,
180216 onPlaybackQualityChange ,
181217 ] ,
@@ -200,9 +236,9 @@ const YoutubeIframe = (props, ref) => {
200236
201237 const source = useMemo ( ( ) => {
202238 const ytScript = MAIN_SCRIPT (
203- videoId ,
204- playList ,
205- initialPlayerParams ,
239+ lastVideoIdRef . current ,
240+ lastPlayListRef . current ,
241+ initialPlayerParamsRef . current ,
206242 allowWebViewZoom ,
207243 contentScale ,
208244 ) ;
@@ -219,15 +255,7 @@ const YoutubeIframe = (props, ref) => {
219255 const data = ytScript . urlEncodedJSON ;
220256
221257 return { uri : base + '?data=' + data } ;
222- } , [
223- videoId ,
224- playList ,
225- useLocalHTML ,
226- contentScale ,
227- baseUrlOverride ,
228- allowWebViewZoom ,
229- initialPlayerParams ,
230- ] ) ;
258+ } , [ useLocalHTML , contentScale , baseUrlOverride , allowWebViewZoom ] ) ;
231259
232260 return (
233261 < View style = { { height, width} } >
@@ -238,7 +266,9 @@ const YoutubeIframe = (props, ref) => {
238266 style = { [ styles . webView , webViewStyle ] }
239267 mediaPlaybackRequiresUserAction = { false }
240268 onShouldStartLoadWithRequest = { onShouldStartLoadWithRequest }
241- allowsFullscreenVideo = { ! initialPlayerParams ?. preventFullScreen }
269+ allowsFullscreenVideo = {
270+ ! initialPlayerParamsRef . current . preventFullScreen
271+ }
242272 userAgent = {
243273 forceAndroidAutoplay
244274 ? Platform . select ( { android : CUSTOM_USER_AGENT , ios : '' } )
0 commit comments