Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
j&o

cleanup ScrollTrigger matchMedia in React

Recommended Posts

Hi there,

 

I am using ScrollTrigger a lot, its a fantastic addition! the only issue I've run into so far is cleaning up when using ScrollTrigger.matchMedia() when un-mounting in my React components. 

I've tried killing all ScrollTrigger instances, and killing timelines individually. simplified setup below:
 

const buildTimeline = () => {
  // ... setup stuff
  ScrollTrigger.saveStyles([boxRef.current, mobileRef.current]);

  ScrollTrigger.matchMedia({
    '(min-width: 720px)': () => {
      if (!boxRef.current) {
        console.log('boxRef does not exist'); 
      }

      ScrollTrigger.create({
        // config stuff
        animation: desktopTimeline.current
          .to(
            // animations
          )
      });
    }, 
    
    '(max-width: 719px)': () => {
      if (!mobileRef.current) {
        console.log('mobileRef does not exist'); 
      }

      ScrollTrigger.create({
        // config stuff
        animation: mobileTimeline.current
          .to(
          // animations
          )
      });
    },
    
  });
  }

  useEffect(() => {
    if (!hasMounted.current) {
      hasMounted.current = true;
      buildTimeline();
    }

    return () => {
      // kill all ScrollTrigger[s]
      ScrollTrigger.getAll().forEach(t => t.kill());

      // try killing individual timelines also
      mobileTimeline.current.kill();
      desktopTimeline.current.kill();
    }
  }, []);

 

This would normally work ok  on ScrollTrigger instances generally - or at least it seems to! - but if I'm using matchMedia I'll still get media query change events firing where the component is unmounted (i.e. navigating to a different route). any idea what I'm missing here? 

Link to comment
Share on other sites

Hey ueno. So you're wanting to disable/kill the matchMedia when the component is unmounted?

 

Can you just kill off ScrollTrigger completely? ScrollTrigger.kill()

 

A minimal demo would likely be helpful in us understanding the usage.

Link to comment
Share on other sites

thanks for the reply Zach :)

 

It's a kind of difficult issue to do a codepen for as it is on unmount after a route change. I can probably whip up something if its unclear as to what I mean but basically using any of the .kill() methods mentioned - and ScrollTrigger.kill() -  doesn't remove ScrollTrigger -- the events are still firing on resize at the defined media queries (in the code posted, <720 & >720) even though that component is unmounted and I have attempted to kill the instance in the ways I have outlined above. 

 

I can send you a DM to a demo if that would help? 

 

Thanks again for getting back to me, I appreciate it!

Link to comment
Share on other sites

3 minutes ago, ueno said:

and ScrollTrigger.kill() -  doesn't remove ScrollTrigger

Are you sure that the method is being called? ScrollTrigger.kill() should completely kill off all of ScrollTrigger, I'd be very surprised if events are still firing afterwards.

 

Keep in mind that the static .kill() method is different than the instance .kill() method.

Link to comment
Share on other sites

Hey there Zach,

 

if i attempt to kill with ScrollTrigger.kill() on unmount, I get the following ts error:
The 'this' context of type 'ScrollTrigger' is not assignable to method's 'this' of type 'PluginScope'.
  Type 'ScrollTrigger' is missing the following properties from type 'PluginScope': _props, _pt, add

 

Is there a different way I should be calling this other than one of these methods?: 

 

import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';

useEffect(() => {
  // call function to setup ScrollTigger;
  
  return () => {
    ScrollTrigger.getAll().forEach(t => t.kill()); // no error but media query events still fire after unmount
    ScrollTrigger.kill(); // error, resize mq events still fire on unmount
    specificTimelineName.kill(); // no error but events still fire on unmount
  }
}, []);

 

Link to comment
Share on other sites

Make sure you're registering ScrollTrigger. But I don't know why that error would be happening.

 

Please try to make a minimal demo that we can check out as given the information I'm not sure if we can help further.

Link to comment
Share on other sites

I am registering it at the _app level (its a next.js app). I can't really post it here but I can send you a link to a simple demo and the source repo as a DM? I would of course post any solution as a result back into the forum. 

Link to comment
Share on other sites

Make sure you're waiting to register (and use) the plugin until the window, document, and <body> exist. 

 

It would be MUCH better if you create a minimal demo rather than just linking us to your actual project. There's usually a lot of extraneous, unrelated code and/or other complexities that may be interfering in your real project. When you create a reduced test case, it often reveals the issue pretty quickly. :)

  • Like 1
Link to comment
Share on other sites

I am registering it correctly :)

 

I'll whip up a pen as soon as i can tomorrow. Let me know if I can send you a link in the meantime? it's as minimal an example as you could imagine - its the "hello world" of matchMedia

Link to comment
Share on other sites

Sure, feel free to shoot me and/or Zach a DM. 

  • Like 1
Link to comment
Share on other sites

Got the demo. I think I see the misunderstanding. 

 

It sounds like you thought that killing a ScrollTrigger that was created inside of one of the .matchMedia() functions would somehow prevent that .matchMedia() function from ever being called again, but that's not how it works. Those are totally separate concepts. Once you set up a matchMedia() at a breakpoint, it will always get called. So the solution with your project would be to just set a variable that you can check inside that function, sorta like:

 

let killed;

ScrollTrigger.matchMedia({
  '(min-width: 720px)': () => {
    if (!killed) { // ONLY IF NOT KILLED!
      ScrollTrigger.create(...); 
    }
  }
});

useEffect(() => {
  ...
  return () => {
      ScrollTrigger.getAll().forEach(t => t.kill());
      killed = true;
    };
}, []);

Does that clear things up? 

  • Like 2
Link to comment
Share on other sites

hey Jack & Zach,

 

Thanks for the assistance. Yep, I assumed that ScrollTrigger.getAll() would kill everything including ScrollTrigger.matchMedia() so I misunderstood the purpose of .kill(); thanks for clearing that up :) 

 

A boolean flag works just fine on unmount, along with killing all the individual ScrollTriggers with a loop over ScrollTrigger.getAll() just like in your example.

 

appreciate the clarification and thanks again for your time!

 

 

  • Like 1
Link to comment
Share on other sites

  • 1 year later...
On 7/25/2020 at 7:24 AM, GreenSock said:
let killed;

ScrollTrigger.matchMedia({
  '(min-width: 720px)': () => {
    if (!killed) { // ONLY IF NOT KILLED!
      ScrollTrigger.create(...); 
    }
  }
});

useEffect(() => {
  ...
  return () => {
      ScrollTrigger.getAll().forEach(t => t.kill());
      killed = true;
    };
}, []);

 

Hi everyone

tried this approach but on mounting again the killed variable value will reset hence the condition will still fire, we somehow need to have a method to kill the matchMedia on unmount, it also cause another issue when remounting back because the previous matchMedia still exist and the scrolltrigger and tweens comes with it is already been destroyed and it throws me an error "Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'." this error will also show when the component has been unmounted and the screen size updated

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.
×