locomotivemtl / locomotive-scroll

🛤 Detection of elements in viewport & smooth scrolling with parallax.

Home Page:https://locomotivemtl.github.io/locomotive-scroll

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Next JS + Loco v5 has some jumps and bottom cuttof

Ahlecss opened this issue · comments

Hi !

I hope you are doing well,

I'm experiencing some bugs with Nextjs 14,

I have long pages, with some images, and regularly, I have some jumps from bottom to mid page,
Also, the scroll can't goes to the bottom of the page.

I'm using this code that reruns Loco on each time the current page changes, thanks to the new pathname hooks.

useEffect(() => {
        (async () => {
            const LocomotiveScroll = (await import('locomotive-scroll')).default;
            loco.current = new LocomotiveScroll({})
        }
        )()
    }, [pathname])

I've read here and there that triggering a "Resize" event could do the work, but it's seems to work randomly.

I've tried to do something like :

window.addEventlistener('DOMContentLoaded', () =>{ loco.current.update() })

But the event is never firing neither.

Plus, I saw that loco.update() is a function that could resolve some things, but I doesn't even exist.

Do you have any on how to resolve that ?

Thanks,
Have a great day !

Hey! Could you provide a Codesandbox URL where the bug occurs? Also are you sure you installed the v5 correctly?
npm install locomotive-scroll@beta

The update method doesn't exist anymore on the v5. Locomotive Scroll v5 automatically handles resize events, eliminating the need for manual resizing.

Hey ! I was beta.11, after npm i again, i'm now in beta.12, but the bug is still there.

It's a bit tricky to show you all the component, but for the interesting part (i guess), it's something like that

function ProjectComponent({ props }) {

    const { category, title, type, madeWith, as, at, year, video, cover, resume, images, link, credits, thanks, reco } = props;


    const ImagesBlock = ({ image }) => {
        const wrapRef = useRef()
        const tl = useRef()
        const [imageRef, inView, entry] = useInView({
            triggerOnce: true,
            threshold: 0,
        })
        useEffect(() => {
            if (tl.current) tl.current.play()
        }, [inView])

        useEffect(() => {
            tl.current = imageAnimation(wrapRef.current, 0)
        }, [wrapRef])

        return (
            <div className="mb-6 md:mb-20" ref={imageRef}>
                <Image src={image} alt={image} width={2000} height={1000} ref={isCreative ? wrapRef : null} className="rounded-3xl"
                />
            </div>
        )
    }

    return (
        <main>
            <div data-scroll-container className={`w-full h-fit relative z-[100]`} id="projectWrapper">
                <div data-scroll className="absolute top-4 left-4 cursor-pointer z-[1000]">
                    <p onClick={handleReturn}>return</p>
                </div>
                <div data-scroll className="h-[100vh] w-full relative">
                    {cover &&
                        <div className="absolute -translate-x-1/2 left-1/2 -translate-y-1/2 top-1/3 w-full px-8 md:top-1/4 md:px-0 md:w-auto">
                            <Image src={cover} alt={"cover"} width={500} height={1000} />
                        </div>
                    }
                </div>

                <div className="contain w-full w-fit /*pb-20">
                    {images && images.map((image, i) => {
                        return <ImagesBlock key={i} image={image} alt='project image' />
                    })}
                </div>

                {link &&
                    <div className="contain pb-20">
                        <a href={link} target="_blank" className="flex uppercase font-semibold tracking-tighter w-fit">See it live <Image src={isCreative ? "/arrowWhite.svg" : "/arrowBlack.svg"} alt="arrow" width={12} height={12} className="ml-2" /></a>
                    </div>
                }

                <div className="h-[100vh] w-full">
                    <Recommandation fakeUseful={reco.useful} fakeCreative={reco.creative} />
                </div>

            </div>
        </main>
    )
}

export default ProjectComponent;

Some images are coming from my props, I'm using useInView hooks library to make them appear, and, beside some divs where I force the height to be 100vh, the height is auto,

Any idea ?

Thanks, have a great day !

Hello !

Did you find anything interesting ?

Happy to know if you've come with somethingperformant.

Have a great day !

Hi,

So for those how encounter the same problem, I came with a solution

Let's say your problem is based on too much images to load, and Lenis is instanciated before all images are loaded, which make the scroll height smaller than it should.

All you have to do, is destroy your last instance, and create another one when all image are loaded.

In my case, I use the onLoad event of <Image /> component, to call a function that count how much images are loaded, compared to how much images should be.

    const imageLoaded = () => {
        countImage.current += 1;
        if (countImage.current === images.length) {
            window.dispatchEvent(new Event('imagesLoaded'))
        }
    }

 [...]

<Image src={image}  onLoad={() => imageLoaded()} height={1000} width={2000}/>

When it's good, I trigger a CustomEvent, to talk with the component that instanciate Locomotive Scroll.

And finally, I just use destroy() and create a new Loco instance again.

    useEffect(() => {
        window.addEventListener('imagesLoaded', restartLoco)
    }, [])

    useEffect(() => {
        restartLoco()
    }, [pathname])
    const restartLoco = () => {
        if (loco.current) loco.current.destroy();

        (async () => {
            const LocomotiveScroll = (await import('locomotive-scroll')).default;
            loco.current = new LocomotiveScroll({})
        }
        )()
    }

Hope it helps !

Have a nice day !

Hi, i am also facing the same issue. i am curious about this loco variable? where is it coming from?