mohitk05 / react-insta-stories

A React component for Instagram like stories
https://mohitk05.github.io/react-insta-stories/
MIT License
1.37k stars 247 forks source link

Preloading images #273

Closed slytter closed 1 year ago

slytter commented 1 year ago

Hey thanks for a cool lib!

Am I right that react-insta-stories does not preload given images? From what I can see from the network profiler, it only loads an image when it is has become active on screen.

@ashmuradyann (#199) have suggested looping trough alle images with display:none, in order to preload the images. But I feel like this could be done more effectively e.g. by prioritizing loading of neighbouring images. Also shouldn't it preloading be a priority feature or what is your take on this @mohitk05?

Thanks

slytter commented 1 year ago

Here is a simple implementation of how it could be done for both video and images, with the Story type. This loads stories in parallel (using Promise.all), but could also be loaded in sequence which would properly make it less expensive and load more 'linearly'.

import {Story} from "react-insta-stories/dist/interfaces";

export const cacheContent = async (contents: Story[]) => {
    const promises = contents.map((content) => {
        return new Promise(function (resolve, reject) {
            const xhr = new XMLHttpRequest();
            if(!content.url) return

            if(content.type === 'video') {
                xhr.responseType = 'blob';
                xhr.onload = function () {
                    resolve(URL.createObjectURL(xhr.response));
                }
                xhr.onerror = reject
            }
            const img = new Image();
            img.src = content.url;
            img.onload = resolve;
            img.onerror = reject;
        })
    })
    await Promise.all(promises);
}

I currently run it in an effect, like so:

    useEffect(() => {
        if(!images) return;

        (async () => {
            await cacheContent(images);
        })()
    }, [images])
mohitk05 commented 1 year ago

Hey @slytter, thanks for creating the issue. I remember implementing a simple preloading logic in the package, but I think it got removed during one of the refactors.

Your solution looks great, and I would do something similar to cache the content early. Any reason for using xhr though? I would assume if you directly create a new Image() or Video() and set the src attribute, it should load similarly, right?

mohitk05 commented 1 year ago

Also, feel free to raise a PR, the solution can be integrated in the package itself. We should provide enough options to configure/disable it though.

slytter commented 1 year ago

Aight, might do a PR during the week :) Yeah you're right with the xhr solution, properly simpler using Video().

Also how should the content load? Maybe it should load x slides forward from the current cursor, such that it is not loading all content at once. Considering doing a preload: boolean prop and a preloadCount: number or something.

edoardoo commented 1 year ago

Cool!

If I remember correctly the preload strategy of the video sources is implemented differently (and not well documented) from browser to browser. The XHR-blob method would then allow, from what I can see, a certain consistency (and certainty).

Also how should the content load? Maybe it should load x slides forward from the current cursor, such that it is not loading all content at once. Considering doing a preload: boolean prop and a preloadCount: number or something.

Absolutely agree. Having it configurable would be extremely useful.

I checked Instagram webpage and they're also using blobs and extensive caching techniques. From what I can see from the network tab and some tests, it looks like they are caching content up to one user more of what it's currently visible.

mohitk05 commented 1 year ago

Closed with #274