Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
DMIND

ScrollTrigger, Locomotive Scroll, React parent-child components problem

Go to solution Solved by ZachSaucier,

Recommended Posts

Hello guys. Please help me with some strange behavior.

 

I have parent component (React) where i initialize ScrollTrigger.scrollerProxy with Locomotive Scroll as you recommended in docs (scrollerProxy). If i try to use scrollTrigger inside that parent component (using useEffect) - everything works fine. But if i use scrollTrigger inside child component and provide the same scroller element (with id #smooth-scroll) then i have an issue.

 

I've already tried:

  • to call ScrollTrigger.refresh() inside child component;
  • make reference (useRef) to locomotive instance in parent component and pass it to child via props;
  • make reference to scroller element using useRef inside parent and pass it to child via props;
  • to initialize ScrollTrigger.scrollerProxy with Locomotive Scroll inside child component - this works, but if i have bunch of elements which calling this initialization - i have terrible performance issue. So i think the best way is to provide only one initialization inside parent (i.e. page) and pass it somehow to child components.

 

Link to Codesandbox (to see smooth scrolling click "Open in new window" icon at top right in browser panel).

 

Maybe someone else have the same problem? What i do wrong in this case?

Link to comment
Share on other sites

  • DMIND changed the title to ScrollTrigger, Locomotive Scroll, React parent-child components problem
  • Solution

Hey DMIND. Thanks for the clear demo.

 

After looking at your demo I had a guess that the child ScrollTrigger was being created before the scrollerProxy. Adding a delay proved that that guess is correct (or at least it works around whatever issue it's having). I am not very familiar with React, but perhaps there's a more React way of making sure that the necessary JS runs in the correct order?

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

13 minutes ago, ZachSaucier said:

Adding a delay proved that that guess is correct (or at least it works around whatever issue it's having).

 

Wow. Thanks a lot Zach for such fast answer!

This little trick fixes everything. I've also tried to use setTimeout with 0ms delay and it also works fine. I spent about 8 hours fixing it... Damn (.

 

I thought that something is wrong with call order inside React's parent-child relations. Maybe there are React fans on board who know how to provide React'ish solution.

Link to comment
Share on other sites

It seems that the correct solution is really using setTimeout or gsap delay call because of call order inside React hooks.

 

I found a good article about hooks which says that "useEffect is called in a bottom-up fashion, so the effects resolve first in the children, and then in the parent." Asynced setTimeout called after all calls executed in stack that's why this solution is fine. We simply change order of effects execution and effect with scrollTrigger inside child component executes after initializing of scrollerProxy in parent - that's our goal!

 

Thank again Zach. I love GSAP and this forum!

  • Like 3
Link to comment
Share on other sites

I'm super late to the party!!! Sorry but I've been extremely busy the past days.

 

@DMIND as you mentioned, yeah the rendering starts from the last branch in the tree and goes up, so in that case you can either use forwardRef in order to pass a child ref to it's parent, in order to  create and control the ScrollTrigger instance in the parent element. Another option, if you need to pass more than one ref from child to parent, is to send a method as a prop to the child element in order to send all the refs you need to pass to the parent component.

 

Yet another option could be to use either a store (Redux, Mobx, React-Query, etc) or the context API, in order to notify the child component, that it can create the ScrollTrigger instance since everything that is supposed to be there for it to work, it's actually there.

 

Finally, I know that sometimes using the-react-way can be quite an issue, but in this case component encapsulation and rendering order are really not working because you're using regular DOM selectors instead of refs to create your instances. This can be quite tedious because sometimes we need to come up with some very convoluted ways to make things work, which brings me to the final suggestion: Learn VueJS :D:D:D

 

Happy Tweening!!! 

  • Like 5
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×