I am using Youtube Player API on my React site. When I try it on the site, it gives this error: TypeError: Cannot read property 'ready' of undefined
. Here is the code I am using:
var player;
function loadVideo() {
window.YT.ready(function () {
new window.YT.Player("player", {
height: "390",
width: "640",
videoId: "M7lc1UVf-VE",
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange,
},
});
});
function onPlayerReady(event) {
event.target.playVideo();
player = event.target;
}
function onPlayerStateChange(event) {
var videoStatuses = Object.entries(window.YT.PlayerState);
console.log(videoStatuses.find((status) => status[1] === event.data)[0]);
}
}
useEffect(() => {
setMaxDuration("06:00");
var tag = document.createElement("script");
tag.src = ";;
var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
loadVideo();
}, []);
Iframe:
<div id="player">
<iframe
title="p"
id="player"
width="560"
height="315"
src=";autoplay=1"
frameBorder="0"
allowFullScreen
></iframe>
</div>
(edited the code to the latest workaround) How can I get this to work?
I am using Youtube Player API on my React site. When I try it on the site, it gives this error: TypeError: Cannot read property 'ready' of undefined
. Here is the code I am using:
var player;
function loadVideo() {
window.YT.ready(function () {
new window.YT.Player("player", {
height: "390",
width: "640",
videoId: "M7lc1UVf-VE",
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange,
},
});
});
function onPlayerReady(event) {
event.target.playVideo();
player = event.target;
}
function onPlayerStateChange(event) {
var videoStatuses = Object.entries(window.YT.PlayerState);
console.log(videoStatuses.find((status) => status[1] === event.data)[0]);
}
}
useEffect(() => {
setMaxDuration("06:00");
var tag = document.createElement("script");
tag.src = "https://www.youtube./iframe_api";
var firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
loadVideo();
}, []);
Iframe:
<div id="player">
<iframe
title="p"
id="player"
width="560"
height="315"
src="https://www.youtube./embed/sGPrx9bjgC8&autoplay=1"
frameBorder="0"
allowFullScreen
></iframe>
</div>
(edited the code to the latest workaround) How can I get this to work?
Share Improve this question edited May 12, 2021 at 10:35 Guerric P 31.9k6 gold badges58 silver badges106 bronze badges asked May 1, 2021 at 7:02 Ajit KumarAjit Kumar 4171 gold badge14 silver badges39 bronze badges 4-
Is this script supposed to create a
YT
global variable? – T J Commented May 1, 2021 at 7:05 - I think it is. I followed this guide: developers.google./youtube/iframe_api_reference – Ajit Kumar Commented May 1, 2021 at 7:06
-
window.YT.Player(...)
– dbuchet Commented May 11, 2021 at 13:16 - 1 Now your problem is solved I reverted your question, according to this: meta.stackoverflow./questions/377812/… In general your question can evolve with debugging details but should not pletely change. Your question will be more useful in its original state for future users that encounter the same problem. And we can discuss about my answer in the ments or in the chat instead of editing the question with its content – Guerric P Commented May 12, 2021 at 10:54
2 Answers
Reset to default 5 +50You have to load the library as suggested by the documentation. The code below loads the library asynchronously, then the library "calls back" your code when ready via the global onYouTubeIframeAPIReady
callback (the name is mandatory).
var tag = document.createElement('script');
tag.src = "https://www.youtube./iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubeIframeAPIReady() {
console.log('Yay, YT exists!', YT);
}
When doing a bit of reverse engineering in the YouTube library code we can see this line (unminified by myself):
const callback = window.onYouTubeIframeAPIReady;
callback && callback();
Which shows how this function is being called and why it doesn't throw any error if it doesn't exist.
As I read your question again, you're using React, so the previous solution might not integrate very well, you might prefer not to use the global callback and use this instead:
const useYoutube = callback => {
useEffect(() => {
if (!window.YT) {
var tag = document.createElement('script');
tag.src = 'https://www.youtube./iframe_api';
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
tag.onload = callback;
} else {
callback();
}
}, []);
};
This custom hook will load the YouTube library only once, lazily (the first time it is needed). You could import it in every ponent that needs it, and use it with useYoutube(loadVideo)
.
Here is a working Stackblitz demo
Works also in local:
The reason the the object shows up in the console, is that the console runs asynchronously from you code. When you have the error YT is not yet loaded, but it has been by the time the console is displayed.
You can prove this be changing your console log to parse the object into a string with JSON.serialise() which will then log the runtime state of the object.