locomotivemtl / locomotive-scroll

πŸ›€ Detection of elements in viewport & smooth scrolling with parallax.
https://locomotivemtl.github.io/locomotive-scroll
MIT License
7.94k stars 1.12k forks source link

Usage with React #13

Open der-lukas opened 5 years ago

der-lukas commented 5 years ago

Is there a way of using this library with React? How would I initialize and target components? Would be awesome if you could supply a minimal setup example!

Thank you!

vsanta commented 5 years ago

Also interested in an example

nathobson commented 5 years ago

I guess something like this: https://codesandbox.io/embed/locomotive-scroll-in-react-k0028.

It's throwing some console errors though but I just put this together really quickly. I've just attached a ref to the container and the I fire the script via the useEffect hook so it fires when the component is mounted.

jaexplorer commented 5 years ago

@nathobson this doesn't work. Its not smooth.

adamcoulombe commented 5 years ago

I use a similar approach as @nathobson to get the element with aref, but I use class components and initiate locomotiveScroll in componentDidMount.

https://codesandbox.io/s/proud-resonance-ou1rz

The main thing to just be aware of when using it with react is if you unmount the component that has rendered the DOM el used by locomotiveScroll, you'll need to destroy your locomotive scroll instance (i think in componentWillUnmount), otherwise you will probably get a bunch of errors.

cytronn commented 5 years ago

Hey, I'm trying to use the module using next.js, and I'm having trouble importing locomotiveScroll. I'm getting an error similar to the issue people had for nuxt.js, document is not defined, but somehow I couldn't find a way to make it work.

millette commented 5 years ago

@cytronn You'll probably need to dynamically import the module so it's not processed server-side (no document there).

aaadamgo commented 5 years ago

@adamcoulombe how do you destroy it on componentWillUnmount?

adamcoulombe commented 5 years ago

@aaadamgo i guess use the destroy method

componentWillUnmount(){
myScroller.destroy()
}
aaadamgo commented 5 years ago

@aaadamgo i guess use the destroy method

componentWillUnmount(){
myScroller.destroy()
}

Thanks Adam, i tried that, or similar anyway. And when it changes page, if i go back to the page where I'm using it, something weird happens where it's likes there's 2 versions of the scrollbar.

see here:

export default class IndexPage extends React.Component {
    constructor(props) {
        super(props);
        const lsRef = null;
    }

    render() {
        return (
            <Animation transitionStatus={this.props.transitionStatus}>
                <div className="ls">
                    ---
                    <Projects />
                </div>
            </Animation>
        );
    }

    componentDidMount() {
        this.lsRef = new LocomotiveScroll({
            el: document.querySelector(".ls"),
            smooth: true,
        });
        window.addEventListener("resize", () => {});
    }

    componentWillUnmount() {
        this.lsRef.destroy();
    }
}
adamcoulombe commented 5 years ago

It’s possible that the destroy method only cleans up the events.

Take a look at the source:

https://github.com/locomotivemtl/locomotive-scroll/blob/4240f83c01d57b60256189ad5960163c3ec5e197/src/scripts/Core.js#L211

Because of this you may also need to manually remove elements that were added like the scrollbar, using some vanilla JS to clean up DOM that locomotive is leaving behind.

Seems like locomotive should be doing this when you destroy- may be worth a separate issue/feature request- unless I’m missing something?

fukou commented 4 years ago

Hello. I am using Next.js and just did what @millette said to dynamically import the module. The error is gone (document is not defined) but still doesn't work. Did I miss something? Here's my code:

import React from "react";
import dynamic from "next/dynamic";

const LocomotiveScroll = dynamic(() => import("locomotive-scroll"), {
  ssr: false
});

class Index extends React.Component {
   componentDidMount() {
    const scroll = new LocomotiveScroll({
      el: document.querySelector(".app"),
      smooth: true
    });
    console.log(scroll);
  }

 render() {
    return (
      <>
        <div className="app">
        ....
        </div>
     </>
     );
  }
}

export default Index;

Thanks in advance!

adamjw3 commented 4 years ago

Has anyone managed to get this to destroy completely.

@adamcoulombe i think i'm experiencing what you stated, when i leave the page with the locomotive-scroll on i'm calling destroy in a react hook but its not removing everything, which is fine on the page i go to but sometimes if i go back to a page with locomotive on it fucks up.

here is an example https://pup.adamwright90.now.sh/

adamcoulombe commented 4 years ago

Has anyone managed to get this to destroy completely.

@adamcoulombe i think i'm experiencing what you stated, when i leave the page with the locomotive-scroll on i'm calling destroy in a react hook but its not removing everything, which is fine on the page i go to but sometimes if i go back to a page with locomotive on it fucks up.

here is an example https://pup.adamwright90.now.sh/

Yeah, if you look at the code in the destroy function, it removes event listeners, but does no DOM cleanup whatsoever, which will likely cause issues

LaurieVince commented 4 years ago

Hi, when I try to use Locomotive Scroll with React, it seems I can't see all my content. But if I resize the window, it works normally. Does someone have this issue too ? Thx, Laurie

elebumm commented 4 years ago

@LaurieVince are you initializing the scroll in the componentDidMount lifecycle method?

LaurieVince commented 4 years ago

Sure, I do.

componentDidMount(){
const scroll = new LocomotiveScroll({
el: document.querySelector('.scroll'),
smooth: true
})
}

I note that it works perfectly when smooth is false. But when it's true, I can't see all my content. That's weird! Does someone else have this issue ?

CorentinBernadou commented 4 years ago

Hi Laurie,

As @Jerek0 said in #66, you need to use update(). But another alternative, when you're using React : You simply can use the setTimeout method to call your scroll, in componentDidMount. Like this :

scroll() {
  const scroll = new LocomotiveScroll({
    el: document.getElementById('#scroll'),
    smooth: true
  }); 
}

componentDidMount(){
  setTimeout(() => {
    this.scroll();
  }, 100);
}

I tested this, and it works perfectly for me.

Jerek0 commented 4 years ago

@imcorentin πŸ‘

If you have an incorrect scroll size (too long / short) at first state on your page: it probably comes from a layout change that occurred after LS init (e.g. an image loaded). Try resizing your window: it probably fixes the scroll.

To fix that for real, you need to call .update() on your LS instance after layout changes to refresh calculations.

In addition to that: 3.3.5 fixes an important issue with .update(). Make sure to upgrade!

ajayns commented 4 years ago

@imcorentin Hey! With Gatsby though, I'd tried a timeout on component mount/useEffect as well as a helper onInitialClientRender which is triggered after the site is loaded, they didn't seem to be solving the issue. The workaround I found if the page has a lot of content loading is calling update() at regular intervals.

@Jerek0 ahh maybe that update could fix the issue, will test it and get back.

ajayns commented 4 years ago

Unfortunately, with the Gatsby case, it still seems like I have to call update() on intervals to ensure that the scroll works correctly for all kinds of pages.

setInterval(() => scroll.update(), 1000);
adamcoulombe commented 4 years ago

Here is an updated example with 3.3.5 showing usage with react and using the update() method when the route changes. I did find that you need to call it after a short timeout (100) sort of like @imcorentin pointed out

https://codesandbox.io/s/icy-wood-96gvz?fontsize=14&hidenavigation=1&theme=dark&view=preview

adamcoulombe commented 4 years ago

Unfortunately, with the Gatsby case, it still seems like I have to call update() on intervals to ensure that the scroll works correctly for all kinds of pages.

setInterval(() => scroll.update(), 1000);

The only thing about calling it repeatedly on interval, is that you have smooth:true, it may make it a little clunky if it updates mid-scroll, it would stop the lerping

mehdilouraoui commented 4 years ago

Hey everyone! I have some troubles when using scrollTo method. I have a main with data-scroll-section which contains 5 sections. Everything works great but when I fire a scrollTo the first section (main's first child), the main doesn't get the new position of the main, so i cannot scroll up after fire a scrollTo.

Also, I cannot access update() method due to react : I create the locomotiveScroll in a use effect.

Is someone have any idea? Many thanks :)

CorentinBernadou commented 4 years ago

Hey @mehdilouraoui, can you please create a Codesandbox to show us your issue with the scrollTo method?

mehdilouraoui commented 4 years ago

Hey @imcorentin I just recreate it (very simpler than the current one in my project): https://codesandbox.io/s/determined-lehmann-w5876

And it works... but not in my project. I attach useState hook to GridInterior component just because I fetch content when the component is mounted.

However, instead of attach the scrollTo to a forwardRef, i just attach it to a div which wrap the component, but nothing works.

I'm not sure this is pretty clear, I just have to investigate more in my project.

elebumm commented 4 years ago

Unfortunately, with the Gatsby case, it still seems like I have to call update() on intervals to ensure that the scroll works correctly for all kinds of pages.

setInterval(() => scroll.update(), 1000);

I had this issue too and also ran into the issue that @adamcoulombe addressed from your reply.

Depending on what kind of site you have, this might work (it did for me). I was able to insert this scroll method into the componentDidMount lifecycle method and then added a slight delay to the update method.

componentDidMount() {
    this.scroll = new LocomotiveScroll({
      el: document.querySelector("body"),
      smooth: true,
    })
    setTimeout(() => this.scroll.update(), 300);
}

I then just destroy the scroll instance and do it on separate pages. If you have dynamic content coming in, (maybe a table that is generated through an AJAX request) this might not work for you, but it worked for me.

mehdilouraoui commented 4 years ago

Hey @elebumm ! Yes it's a solution but I don't want to fix with a timeout because as you said, I fetch content from an API. I'm currently trying to update the locomotive scroll (with a boolean in a state) once the content is fully loaded. Should works

Adarsh777 commented 4 years ago

How to implement it in Gatsby ?

dngraphisme commented 4 years ago

Hello all,

Thank you for this feed :) Regarding LM on Wordpress I did this:

At the end of my preloader I call a callback with an onComplete: scroll.update ();

To always have the right height, I had woocommerce pages that scrolled the content after my footer.

And during the transition with barbajs I destroy LM at hooks.beforeLeave and I reinit it at the entrance of the new DOM .hooks.after

fcisio commented 4 years ago

Hi, I currently have Locomotive Scroll working in Gatsby, I have some snippets down below.

But I'm posting on here regarding the data-scroll-call and more specifically to figure out how to use it with Gatsby.

I basically init the library on the client and store the instance in window. I can then simply do stuff like updating the scroll by calling () => typeof window !== 'undefined' && window.scroll.update().

Here's my issue, when trying to call an event inside a component:

window.scroll.on('call', func => {
    func === 'testCall' && console.log('Event Called')
})

I get an error ⚠️ TypeError: "window.scroll.on is not a function"

Any pointers?


My working Gatsby config

import LocomotiveScroll from 'locomotive-scroll'

//

useEffect(() => {
    let locomotiveScroll
    locomotiveScroll = new LocomotiveScroll({
      el: document.querySelector('#___gatsby),
      ...scroll.options,
    })
    locomotiveScroll.update()

    // Exposing to the global scope
    window.scroll = locomotiveScroll

    return () => {
      if (locomotiveScroll) locomotiveScroll.destroy()
    }
 }, [location])
// Callback on routeChange

In gatsby-node.js

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === 'build-html' || stage === 'develop-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /locomotive-scroll/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

πŸŽ‰ Now it works and you can reference the instance like so () => typeof window !== 'undefined' && window.scroll.update().

CorentinBernadou commented 4 years ago

Hey @fcisio, did you try this (instead of window.scroll)?

useEffect(() => {
    const locomotiveScroll = new LocomotiveScroll({
      el: document.querySelector(myScrollContainer)
    })

    locomotiveScroll.on('call', value => {
      value === 'testCall' && console.log('Scroll function called');
    });
 }, [])
thijszijlstra commented 4 years ago

Hi, I currently have Locomotive Scroll working in Gatsby, I have some snippets down below.

But I'm posting on here regarding the data-scroll-call and more specifically to figure out how to use it with Gatsby.

I basically init the library on the client and store the instance in window. I can then simply do stuff like updating the scroll by calling () => typeof window !== 'undefined' && window.scroll.update().

Here's my issue, when trying to call an event inside a component:

window.scroll.on('call', func => {
    func === 'testCall' && console.log('Event Called')
})

I get an error ⚠️ TypeError: "window.scroll.on is not a function"

Any pointers?

My working Gatsby config

import LocomotiveScroll from 'locomotive-scroll'

//

useEffect(() => {
    let locomotiveScroll
    locomotiveScroll = new LocomotiveScroll({
      el: document.querySelector('#___gatsby),
      ...scroll.options,
    })
    locomotiveScroll.update()

    // Exposing to the global scope
    window.scroll = locomotiveScroll

    return () => {
      if (locomotiveScroll) locomotiveScroll.destroy()
    }
 }, [location])
// Callback on routeChange

In gatsby-node.js

exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === 'build-html' || stage === 'develop-html') {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /locomotive-scroll/,
            use: loaders.null(),
          },
        ],
      },
    })
  }
}

πŸŽ‰ Now it works and you can reference the instance like so () => typeof window !== 'undefined' && window.scroll.update().

I can't get your config files to work, do you mind sharing the files?

samuelgoddard commented 4 years ago

Does anyone here have a repo with a working Gatsby example? I can get it working fine but everything messes up when I navigate to a new page. Thank you!

fcisio commented 4 years ago

Does anyone here have a repo with a working Gatsby example? I can get it working fine but everything messes up when I navigate to a new page. Thank you!

Hi, I have just put together a repo, I hope this can help many people πŸŽ‰

https://github.com/fcisio/gatsby-locomotivescroll-starter

samuelgoddard commented 4 years ago

Hey @fcisio this works absolutely amazingly, thank you so much! The only thing i've found is when using the back and forward functions of the browser, it doesn't seem to refresh the container heights for locomotive, do you have any idea how you would add that functionality? Thanks again

samuelgoddard commented 4 years ago

Hmm actually ignore me sorry @fcisio! This seems to be an issue with when i'm using leave animation transitions with Framer Motion... trying to figure it out now. Thanks again :)

19h47 commented 4 years ago

@fcisio Thank you so much, it work like a charm!

Arshazar commented 4 years ago

@fcisio hey, I used your code, but, it doesn't work on my page which has several gsap timelines... it stucks at the top of the page, unable to scroll and timeline not working with smooth=true though I added updateScroll as following:

const updateScroll = () => isBrowser && window.scroll.update()
.
.
.
.
.
gsap.registerPlugin(ScrollTrigger)
        const tl = gsap.timeline({
            scrollTrigger: {
                start: 'top -20',
            },
        })

        gsap.from('.about-paragraphs #para1', vars)
        tl.from('.about-paragraphs #para2', vars)
            .from('.about-paragraphs #para3', vars)
            .from('.about-paragraphs #para4', vars)
            .call(() => updateScroll())

I know I'm wrong w sth, I don't know what!

fcisio commented 4 years ago

Hi @Arshazar

Using smooth: true means that native scroll will not be used. Instead, a container element is animated to simulate the scroll behavior.

I believe the issue is not the timelines themselves, but the use of scrollTrigger which I think will only work with native scroll.

In this scenario, you will only be able to use one or the other. I hope I was able to answer your question.

Arshazar commented 4 years ago

@fcisio Thank u, mate!

edoardolunardi commented 4 years ago

@Arshazar and @fcisio fyi, you can integrate both. Take a look here

Hope this helps πŸ‘

Arshazar commented 4 years ago

Hey @edoardolunardi , I actually wanted to do so, but I assumed it'd be a headache to try! Anyway, it really helped! thank you...

johnchourajr commented 4 years ago

Here is an updated example with 3.3.5 showing usage with react and using the update() method when the route changes. I did find that you need to call it after a short timeout (100) sort of like @imcorentin pointed out

https://codesandbox.io/s/icy-wood-96gvz?fontsize=14&hidenavigation=1&theme=dark&view=preview

Here is a hooks implementation of this same thing https://codesandbox.io/s/nostalgic-cannon-7tk08?file=/src/App.js

cytronn commented 4 years ago

Hello. I am using Next.js and just did what @millette said to dynamically import the module. The error is gone (document is not defined) but still doesn't work. Did I miss something? Here's my code:

import React from "react";
import dynamic from "next/dynamic";

const LocomotiveScroll = dynamic(() => import("locomotive-scroll"), {
  ssr: false
});

class Index extends React.Component {
   componentDidMount() {
    const scroll = new LocomotiveScroll({
      el: document.querySelector(".app"),
      smooth: true
    });
    console.log(scroll);
  }

 render() {
    return (
      <>
        <div className="app">
        ....
        </div>
     </>
     );
  }
}

export default Index;

Thanks in advance!

did you get it to work?

antoinelin commented 4 years ago

Hello. I am using Next.js and just did what @millette said to dynamically import the module. The error is gone (document is not defined) but still doesn't work. Did I miss something? Here's my code:

import React from "react";
import dynamic from "next/dynamic";

const LocomotiveScroll = dynamic(() => import("locomotive-scroll"), {
  ssr: false
});

class Index extends React.Component {
   componentDidMount() {
    const scroll = new LocomotiveScroll({
      el: document.querySelector(".app"),
      smooth: true
    });
    console.log(scroll);
  }

 render() {
    return (
      <>
        <div className="app">
        ....
        </div>
     </>
     );
  }
}

export default Index;

Thanks in advance!

did you get it to work?

πŸ–– NextJS dynamic import is used to dynamically import React components, not classes. This way you will need to load it like <LocomotiveScroll /> in your code.

Succeed to get it working with NextJS doing like this :

import React, { createContext, useEffect, useState } from 'react'
import { Scroll, LocomotiveScrollOptions } from 'locomotive-scroll'

interface ContextProps {
  scroll: Scroll | null
}

export const SmoothScrollContext = createContext<ContextProps>({
  scroll: null,
})

interface Props {
  options: LocomotiveScrollOptions
}

export const SmoothScrollProvider: React.FC<Props> = ({ children, options }) => {
  const [scroll, setScroll] = useState<Scroll | null>(null)

  useEffect(() => {
    ;(async () => {
      try {
        const LocomotiveScroll = (await import('locomotive-scroll')).default

        setScroll(
          new LocomotiveScroll({
            el: document.querySelector('[data-scroll-container]') ?? undefined,
            ...options,
          })
        )
      } catch (error) {
        throw Error(`[SmoothScrollProvider]: ${error}`)
      }
    })()

    return () => {
      scroll?.destroy()
    }
  }, [])

  return <SmoothScrollContext.Provider value={{ scroll }}>{children}</SmoothScrollContext.Provider>
}

SmoothScrollContext.displayName = 'SmoothScrollContext'
SmoothScrollProvider.displayName = 'SmoothScrollProvider'

I'm using a context here for being able to access to the instance on all my childs components. 🚨 Don't forget to use data-scroll-section or you will face weird behaviours. Give me a bit of time so I will wrap all of this on an NPM package.

Types coming from : Link

rushjam commented 4 years ago

Hello. I am using Next.js and just did what @millette said to dynamically import the module. The error is gone (document is not defined) but still doesn't work. Did I miss something? Here's my code:

import React from "react";
import dynamic from "next/dynamic";

const LocomotiveScroll = dynamic(() => import("locomotive-scroll"), {
  ssr: false
});

class Index extends React.Component {
   componentDidMount() {
    const scroll = new LocomotiveScroll({
      el: document.querySelector(".app"),
      smooth: true
    });
    console.log(scroll);
  }

 render() {
    return (
      <>
        <div className="app">
        ....
        </div>
     </>
     );
  }
}

export default Index;

Thanks in advance!

did you get it to work?

πŸ–– NextJS dynamic import is used to dynamically import React components, not classes. This way you will need to load it like <LocomotiveScroll /> in your code.

Succeed to get it working with NextJS doing like this :

import React, { createContext, useEffect, useState } from 'react'
import { Scroll, LocomotiveScrollOptions } from 'locomotive-scroll'

interface ContextProps {
  scroll: Scroll | null
}

export const SmoothScrollContext = createContext<ContextProps>({
  scroll: null,
})

interface Props {
  options: LocomotiveScrollOptions
}

export const SmoothScrollProvider: React.FC<Props> = ({ children, options }) => {
  const [scroll, setScroll] = useState<Scroll | null>(null)

  useEffect(() => {
    ;(async () => {
      try {
        const LocomotiveScroll = (await import('locomotive-scroll')).default

        setScroll(
          new LocomotiveScroll({
            el: document.querySelector('[data-scroll-container]') ?? undefined,
            ...options,
          })
        )
      } catch (error) {
        throw Error(`[SmoothScrollProvider]: ${error}`)
      }
    })()

    return () => {
      scroll?.destroy()
    }
  }, [])

  return <SmoothScrollContext.Provider value={{ scroll }}>{children}</SmoothScrollContext.Provider>
}

SmoothScrollContext.displayName = 'SmoothScrollContext'
SmoothScrollProvider.displayName = 'SmoothScrollProvider'

I'm using a context here for being able to access to the instance on all my childs components. 🚨 Don't forget to use data-scroll-section or you will face weird behaviours. Give me a bit of time so I will wrap all of this on an NPM package.

Types coming from : Link

It would be much better if you provide working example. Do you have any ?

antoinelin commented 4 years ago

Hello. I am using Next.js and just did what @millette said to dynamically import the module. The error is gone (document is not defined) but still doesn't work. Did I miss something? Here's my code:

import React from "react";
import dynamic from "next/dynamic";

const LocomotiveScroll = dynamic(() => import("locomotive-scroll"), {
  ssr: false
});

class Index extends React.Component {
   componentDidMount() {
    const scroll = new LocomotiveScroll({
      el: document.querySelector(".app"),
      smooth: true
    });
    console.log(scroll);
  }

 render() {
    return (
      <>
        <div className="app">
        ....
        </div>
     </>
     );
  }
}

export default Index;

Thanks in advance!

did you get it to work?

πŸ–– NextJS dynamic import is used to dynamically import React components, not classes. This way you will need to load it like <LocomotiveScroll /> in your code. Succeed to get it working with NextJS doing like this :

import React, { createContext, useEffect, useState } from 'react'
import { Scroll, LocomotiveScrollOptions } from 'locomotive-scroll'

interface ContextProps {
  scroll: Scroll | null
}

export const SmoothScrollContext = createContext<ContextProps>({
  scroll: null,
})

interface Props {
  options: LocomotiveScrollOptions
}

export const SmoothScrollProvider: React.FC<Props> = ({ children, options }) => {
  const [scroll, setScroll] = useState<Scroll | null>(null)

  useEffect(() => {
    ;(async () => {
      try {
        const LocomotiveScroll = (await import('locomotive-scroll')).default

        setScroll(
          new LocomotiveScroll({
            el: document.querySelector('[data-scroll-container]') ?? undefined,
            ...options,
          })
        )
      } catch (error) {
        throw Error(`[SmoothScrollProvider]: ${error}`)
      }
    })()

    return () => {
      scroll?.destroy()
    }
  }, [])

  return <SmoothScrollContext.Provider value={{ scroll }}>{children}</SmoothScrollContext.Provider>
}

SmoothScrollContext.displayName = 'SmoothScrollContext'
SmoothScrollProvider.displayName = 'SmoothScrollProvider'

I'm using a context here for being able to access to the instance on all my childs components. 🚨 Don't forget to use data-scroll-section or you will face weird behaviours. Give me a bit of time so I will wrap all of this on an NPM package. Types coming from : Link

It would be much better if you provide working example. Do you have any ?

Sandbox link here : https://codesandbox.io/s/nextjs-with-locomotive-scroll-nl7vs πŸš€

mxmtsk commented 4 years ago

@toinelin This works fine on a single page but as soon as you route to other pages it falls apart for me. Since scroll is not in your effect dependencies, it will be always null which makes destroy undefined all the time, hence why you end up with multiple instances when you start to navigate around the page.

    return () => {
      console.log(scroll); // this is always null
      scroll && scroll.destroy()
    }

I got much better results by moving the Provider to _app and trying to call update on the scroller on route changes but I get issues with height calculation there, when rendering is not done before update is called. Also tried periodically calling update but that makes scrolling not so smooth anymore.

antoinelin commented 4 years ago

@mxmtsk Good point for the useEffect the scroll instance on the return still the same as the default one from context which is null before the client is ready and not updated by the assignation, I missed that. But as far as I understand, the scroll instance should be overwriting itself each time you change a page and not colliding itself in any ways (which is not what we want too obviously). One solution I see to properly ensure that the instance is destroyed each time you leave the page could be to add scroll as effect dependency and check if scroll is null before calling a new instance to avoid unwanted loop crashes. I did not explore as far the solution with the Provider on _app as I wanted something possibly modular between pages. For the height calculation, did you try using useLayoutEffect instead of useEffect ? Omh, I had issues and weird behaviours by forgetting to add data-scroll-section on each pages, if it could be a trail for you to explore I updated the sandbox with a new page if you want to try it.

mxmtsk commented 4 years ago

@toinelin Sure, if you have time to provide a working example with two pages it would help. I would try it out in our "real world" page with complex page structure immediately. Would love to find a robust implementation for locomotive scroll in next.js :)