GSAP ScrollTrigger conflicting array Filter as triggers not killed

183 Views Asked by At

I am having some issues with the GSAP ScrollTrigger functionality and making use of the array filter function.

When I click on a filter option it gives me the following error:

NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

Here is my code:

const [selectedTag, setSelectedTag] = useState(null);
const [filteredCaseStudies, setFilteredCaseStudies] = useState(caseStudies);

gsap.registerPlugin(ScrollTrigger);

useEffect(() => {
  let mm = gsap.matchMedia();
  const panels = gsap.utils.toArray<HTMLElement>(".panel")

  mm.add("(min-width: 768px)", () => {
    panels.forEach((panel, i) => {
      const isLastPanel = i === panels.length - 1;

      const trigger = gsap.to(panel, {
          id: i,
          scrollTrigger: {
            trigger: panel,
            snap: 0,
            pin: true,
            pinSpacing: false,
            start: "top top",
            end: isLastPanel ? "bottom bottom" : "",
            onEnterBack: () => {
              if (isLastPanel) {
                // Remove pinning when the last panel enters the viewport
                trigger.kill();
              }
            },
          },
      });
    });
  });
}, []);

useEffect(() => {
  if (selectedTag) {
    const filtered = caseStudies.filter((caseStudy) =>
      caseStudy.tags.includes(selectedTag)
    ); 
    
    setFilteredCaseStudies(filtered)
  } else {
    setFilteredCaseStudies(caseStudies);
  }
}, [selectedTag, caseStudies]);

As far as I'm aware, I believe the issue is because by the triggers not being killed since the filtered array list will remove elements from the DOM that have active triggers, but I could be wrong any help or pointers is appreciated.

1

There are 1 best solutions below

1
Hashan Hemachandra On

When you filter the case studies and update filteredCaseStudies, it's likely that some DOM elements are being removed or replaced. However, if these elements have ScrollTriggers attached to them, and these triggers are not properly killed or updated to reflect the new DOM state, you'll encounter errors like the one you're seeing.

Whenever your selectedTag changes and you filter caseStudies, ensure that you update or recreate the ScrollTriggers for the new set of elements in filteredCaseStudies.

useEffect(() => {
  let triggers = [];

  function setupScrollTriggers() {
    let panels = gsap.utils.toArray<HTMLElement>(".panel");

    panels.forEach((panel, i) => {
      const isLastPanel = i === panels.length - 1;
      const trigger = gsap.to(panel, {
        id: i,
        scrollTrigger: {
          trigger: panel,
          snap: 0,
          pin: true,
          pinSpacing: false,
          start: "top top",
          end: isLastPanel ? "bottom bottom" : "",
          onEnterBack: () => {
            if (isLastPanel) {
              trigger.kill();
            }
          },
        },
      });

      triggers.push(trigger);
    });
  }

  setupScrollTriggers();

  return () => {
    // Cleanup: Kill all triggers when the component unmounts
    triggers.forEach(trigger => trigger.scrollTrigger.kill());
  };
}, []);

useEffect(() => {
  // When selectedTag changes, update the filtered case studies and reset triggers
  if (selectedTag) {
    const filtered = caseStudies.filter(caseStudy =>
      caseStudy.tags.includes(selectedTag)
    );

    setFilteredCaseStudies(filtered);
  } else {
    setFilteredCaseStudies(caseStudies);
  }

  // Kill existing triggers and setup new ones
  triggers.forEach(trigger => trigger.scrollTrigger.kill());
  setupScrollTriggers();
}, [selectedTag, caseStudies]);