I am using LocomotiveScroll in a React application and I have created a custom hook called useLocoScroll
to handle the initialization and destruction of the LocomotiveScroll instance in order to make LocomotiveScroll work with gsap's ScrollTrigger. The hook works fine and I can use it to enable smooth scrolling and also use the ScrollTrigger in my app.
However, I now need to access the LocomotiveScroll instance from outside the hook so that I can call its methods directly. Specifically, I want to be able to call the scrollTo method of the instance to scroll to specific positions in the page, and I also want to be able to force a scroll to the top of the page whenever React Router changes routes.
I have created a function that does exactly that but it uses a new instance of the Locomotive scroll, while this worked fine if the custom hook is set to false
and the first instance of the LocomotiveScroll does not exist. When the custom hook is set to true
it no longer works. I am just assuming that that's because I am creating 2 instances of LocomotiveScroll.
useLocoScroll(true);
const { pathname } = useLocation();
const scrollRef = useRef(null);
useEffect(() => {
const scroll = new LocomotiveScroll();
scrollRef.current = scroll;
if (scrollRef.current) {
scrollRef.current.scrollTo('top', {
offset: 0,
duration: 600,
easing: [0.25, 0.0, 0.35, 1.0],
disableLerp: true,
});
}
}, [pathname]);
I have tried adding the function to the LocomotiveScroll instance inside the hook and returning it, but I can't seem to get it to work.
This is the custom hook:
import { useState, useLayoutEffect } from 'react';
import LocomotiveScroll from 'locomotive-scroll';
import gsap from 'gsap';
import ScrollTrigger from 'gsap/ScrollTrigger';
const useLocoScroll = (start) => {
gsap.registerPlugin(ScrollTrigger);
useLayoutEffect(() => {
if (!start) return;
const scrollEl = document.querySelector('.App');
let locoScroll = new LocomotiveScroll({
el: scrollEl,
smoothMobile: false,
smooth: true,
multiplier: 1,
});
locoScroll.on('scroll', ScrollTrigger.update);
ScrollTrigger.scrollerProxy(scrollEl, {
scrollTop(value) {
if (locoScroll) {
return arguments.length
? locoScroll.scrollTo(value, 0, 0)
: locoScroll.scroll.instance.scroll.y;
}
return null;
},
scrollLeft(value) {
if (locoScroll) {
return arguments.length
? locoScroll.scrollTo(value, 0, 0)
: locoScroll.scroll.instance.scroll.x;
}
return null;
},
getBoundingClientRect() {
return {
top: 0,
left: 0,
width: window.innerWidth,
height: window.innerHeight,
};
},
pinType: document.querySelector('.App').style.transform
? 'transform'
: 'fixed',
});
const locoScrollUpdate = () => {
if (locoScroll) {
locoScroll.update();
}
};
new ResizeObserver(() => {
if (locoScroll) {
locoScroll.update();
}
}).observe(document.querySelector('[data-scroll-container]'));
ScrollTrigger.addEventListener('refresh', locoScrollUpdate);
ScrollTrigger.refresh();
return () => {
if (locoScroll) {
ScrollTrigger.removeEventListener('refresh', locoScrollUpdate);
locoScroll.destroy();
locoScroll = null;
}
};
}, [start]);
};
export default useLocoScroll;
This is what I've tried
// ...rest of the code
const scrollToTop = () => {
if (locoScroll) {
locoScroll.scrollTo(0, 0, 0);
}
};
ScrollTrigger.addEventListener('refresh', locoScrollUpdate);
ScrollTrigger.refresh();
return () => {
if (locoScroll) {
ScrollTrigger.removeEventListener('refresh', locoScrollUpdate);
locoScroll.destroy();
locoScroll = null;
}
};
}, [start]);
return scrollToTop;
};
export default useLocoScroll;
The error I receive is saying that scrollToTop is not defined.
How can I modify this hook to allow me to access and use the LocomotiveScroll instance outside the hook?