locomotive-scroll
locomotive-scroll copied to clipboard
Usage with React
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!
Also interested in an example
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.
@nathobson this doesn't work. Its not smooth.
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.
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.
@cytronn You'll probably need to dynamically import the module so it's not processed server-side (no document
there).
@adamcoulombe how do you destroy it on componentWillUnmount?
@aaadamgo i guess use the destroy method
componentWillUnmount(){
myScroller.destroy()
}
@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();
}
}
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?
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!
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/
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
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
@LaurieVince are you initializing the scroll in the componentDidMount
lifecycle method?
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 ?
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.
@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!
@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.
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);
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
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
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 :)
Hey @mehdilouraoui, can you please create a Codesandbox to show us your issue with the scrollTo method?
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.
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.
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
How to implement it in Gatsby ?
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
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()
.