I have a React app with a component that loads different videos depending on user input. There are only 4 or 5 small videos, so I'd like to pre-fetch all of them when the browser is inactive.
Within my component, I have:
<video src={this.props.video} type="video/mp4" />
In my index.html, I have a line in the head for a video:
<link rel="prefetch" as="video/mp4" href="link/to/my/video.mp4">
However, this doesn't work. Looking at the console, I can see that the video is fetched (with a 200 status) but not stored in the cache (size is 5 Mb for the response, 0 Mb for on disk). When I provide user input and the component needs to display that video, it is fetched again which takes a few seconds.
PS - The reason I'm not trying to use preload on the video element is because preload only works if the page you are looking at has the video in it. In my case, I want to load the videos even if they are not required for the current page.
Update: I made a pen where you can see that the video isn't pre-fetched despite the use of a link tag in the head.
The goal of prefetching is to make data fetch before the user navigates to a page or attempts to load some known content. There are a handful of situations that you may want to do this, but some very common use cases are: User hovers over a navigation element. User hovers over a list element that is a link.
To solve this react itself has a native solution, which is code-splitting and lazy loading. Which allows splitting bundle files into a smaller size. The best place to introduce code splitting is in routes. Route-based code splitting solve half of the issues.
To add a background video with React, we can add the video element with the autoPlay prop. We add the video element with the loop prop to make the video replay after it's finished. And the autoPlay prop makes the video start automatically when we load the page.
In your situation, you can make an AJAX request and create blob URL from the response of that request.
You can see from my code pen
function playVideo() {
var video = document.getElementById('video')
if (video) {
video.play().then(_ => {
console.log('played!')
});
}
}
function onSuccess(url) {
console.log(url);
var video = document.createElement('VIDEO')
if (!video.src) {
video.id = 'video';
document.body.appendChild(video);
video.src = url
}
}
function onProgress() {
}
function onError() {
}
prefetch_file('https://raw.githubusercontent.com/FilePlayer/test/gh-pages/sw_360_lq.mp4', onSuccess, onProgress, onError)
function prefetch_file(url,
fetched_callback,
progress_callback,
error_callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "blob";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
var URL = window.URL || window.webkitURL;
var blob_url = URL.createObjectURL(xhr.response);
fetched_callback(blob_url);
} else {
error_callback();
}
}, false);
var prev_pc = 0;
xhr.addEventListener("progress", function (event) {
if (event.lengthComputable) {
var pc = Math.round((event.loaded / event.total) * 100);
if (pc != prev_pc) {
prev_pc = pc;
progress_callback(pc);
}
}
});
xhr.send();
}
The disadvantage of this approach is that it will not work if the video doesn't allow CORS for your site.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With