Implementing click events to control GSAP animations in Next.js

I'm having trouble figuring out how to pause/start an animation using GSAP in Nextjs. Specifically, I can't seem to work with a tl.current outside the useEffect hook within this component. My goal is that when I click on the first .imgWrapper element, I want the tl.current to toggle and either pause or start the animation. However, despite my efforts, I haven't been able to make it work.

export const Projects = () => {
  const projects = useRef();
  const projectTitle = useRef(null);
  const tl = useRef();
  const q = gsap.utils.selector(projects);

  useEffect(() => {
    tl.current = gsap
      .timeline()
      .from(q(".singleProject:nth-child(2)"), {
        y: 2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        paused: false,
      })
      .to(q(".singleProject:nth-child(2)"), {
        y: -2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        paused: false,
      });
    tl.current = gsap
      .timeline()
      .from(q(".singleProject:nth-child(3)"), {
        y: 2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 1,
      })
      .to(q(".singleProject:nth-child(3)"), {
        y: -2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 1,
      });
    tl.current = gsap
      .timeline()
      .from(q(".singleProject:nth-child(4)"), {
        y: 2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 2,
      })
      .to(q(".singleProject:nth-child(4)"), {
        y: -2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 2,
      });
   
  }, []);
  const [animate_1, setAnimate_1] = useState(false);
  const [animate_2, setAnimate_2] = useState(false);
  const [animate_3, setAnimate_3] = useState(false);

  return (
    <section
      ref={projects}
      id="projects"
      className={`${animate_1 && "animated_1"} ${animate_2 && "animated_2"} ${animate_3 && "animated_3"} w_100 h_100vh flex flexColumn flexAlignCenter flexCenter p4em`}
    >
      <div className="projectsLoading flex flexCenter flexAlignCenter w_100 h_100">
        <h2>LOADING PROJECTS</h2>
      </div>
      <div className={`singleProject w_100 flex flexStart`}>
        <div className="imgWrapper" onClick={() => some code}>
          <img src={"https://www.aimanalmureish.com/img/lego.jpg"} />
        </div>
      </div>
      <div className="singleProject w_100 flex flexEnd">
        <div className="imgWrapper">
          <img
            onClick={() => {
              setAnimate_2(!animate_2);
            }}
            src={"https://www.aimanalmureish.com/img/jordan.png"}
          />
        </div>
      </div>
      <div className="singleProject w_100 flex flexStart">
        <div className="imgWrapper">
          <img
            onClick={() => setAnimate_3(!animate_3)}
            src={"https://www.aimanalmureish.com/img/ferrari.png"}
          />
        </div>
      </div>
    </section>
  );
};

After console logging tl.current.pause(), this is what shows up in the console https://i.stack.imgur.com/xo0LR.png.

Any assistance would be greatly appreciated. Thank you!

Answer №1

This updated answer provides a solution to the question.

The code snippet below shows how the Projects component is implemented:

export const Projects = () => {
  const projects = useRef();
  const projectTitle = useRef(null);
  const tl = useRef();
  const first = useRef();
  const second = useRef();
  const third = useRef();
  const q = gsap.utils.selector(projects);

  useEffect(() => {
    // Animation for first child
    first.current = gsap
      .timeline()
      .from(q(".singleProject:nth-child(2)"), {
        y: 2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        paused: false,
      })
      .to(q(".singleProject:nth-child(2)"), {
        y: -2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        paused: false,
      });

    // Animation for second child
    second.current = gsap
      .timeline()
      .from(q(".singleProject:nth-child(3)"), {
        y: 2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 1,
      })
      .to(q(".singleProject:nth-child(3)"), {
        y: -2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 1,
      });

    // Animation for third child
    third.current = gsap
      .timeline()
      .from(q(".singleProject:nth-child(4)"), {
        y: 2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 2,
      })
      .to(q(".singleProject:nth-child(4)"), {
        y: -2000,
        ease: Linear.easeNone,
        opacity: 1,
        duration: 20,
        repeat: -1,
        delay: 2,
      });
  }, []);
  
  // State variables for animation control
  const [animate_1, setAnimate_1] = useState(false);
  const [animate_2, setAnimate_2] = useState(false);
  const [animate_3, setAnimate_3] = useState(false);

  return (
    <section
      ref={projects}
      id="projects"
      className={`${animate_1 && "animated_1"} ${animate_2 && "animated_2"} ${
        animate_3 && "animated_3"
      }
       w_100 h_100vh flex flexColumn flexAlignCenter flexCenter p4em`}
    >
      <div className="projectsLoading flex flexCenter flexAlignCenter w_100 h_100">
        <h2>LOADING PROJECTS</h2>
      </div>
      <div ref={first} className={`singleProject w_100 flex flexStart`}>
        <div
          className="imgWrapper"
          onMouseEnter={() => {
            first.current.paused(true);
            second.current.paused(true);
            third.current.paused(true);
          }}
          onMouseLeave={() => {
            first.current.paused(false);
            second.current.paused(false);
            third.current.paused(false);
          }}
        >
          <img src={"https://www.aimanalmureish.com/img/lego.jpg"} />
        </div>
        {/* <div className="projectDetails flex flexColumn flexAlignStart flexCenter">
          <h2 ref={projectTitle}>PROJECT TITLE</h2>
          <p>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem,
            veniam! Reiciendis, totam explicabo quisquam dolorem quibusdam sit
            dignissimos corporis veniam.
          </p>
        </div> */}
      </div>
      <div ref={second} className="singleProject w_100 flex flexEnd">
        <div className="imgWrapper">
          <img
            onMouseEnter={() => {
              first.current.paused(true);
              second.current.paused(true);
              third.current.paused(true);
            }}
            onMouseLeave={() => {
              first.current.paused(false);
              second.current.paused(false);
              third.current.paused(false);
            }}
            src={"https://www.aimanalmureish.com/img/jordan.png"}
          />
        </div>

        {/* <div className="projectDetails flex flexColumn flexAlignStart flexCenter">
          <h2 ref={projectTitle}>PROJECT TITLE</h2>
          <p>
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem,
            veniam! Reiciendis, totam explicabo quisquam dolorem quibusdam sit
            dignissimos corporis veniam.
          </p>
        </div> */}
      </div>
      <div ref={third} className="singleProject w_100 flex flexStart">
        <div className="imgWrapper">
          <img
            onMouseEnter={() => {
              first.current.paused(true);
              second.current.paused(true);
              third.current.paused(true);
            }}
            onMouseLeave={() => {
              first.current.paused(false);
              second.current.paused(false);
              third.current.paused(false);
            }}
            src={"https://www.aimanalmureish.com/img/ferrari.png"}
          />
        </div>
      </div>
    </section>
  );
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The function inArray() in jQuery will return a value of -1 when an array consists of

When using jQuery inArray, if the array contains only one element, it will return -1. var a = Array(1); console.log($.inArray(1,a)); This result is -1. However, if the array has 2 or more elements, it functions correctly. var a = Array(1,2,3); console.l ...

The version of caniuse-lite in Browserslist is no longer current. To update, please execute the following command: `y

I am encountering an error message in 2 of my Next.js applications that says: Browserslist: caniuse-lite is outdated. Please run next command 'yarn upgrade'. This message appears when I execute commands like yarn dev, yarn start, or yarn build. T ...

Update object properties in Angular controller dynamically

Take a look at my simple plunker Within the code, I am attempting to link a scope variable to an object property. $scope.name = 'World'; var obj = { "name":$scope.name } $scope.$watch('name', function(){ console.log(obj["name"]); ...

What is the best way to adjust a wide HTML table to make it narrow enough to fit perfectly within the screen width?

I need assistance with formatting an HTML table that contains multiple columns: <table id="req_header" border="2" style="overflow: auto;"> <tr> <th><i class="fa fa-solid fa-check"> ...

Ajax appends a single row, not an entire array

My ajax function is retrieving an array of data from the backend, but when I try to display it in the blade, only one row appears instead of multiple rows. List of Problems Only 1 row is appended by ajax The select option is empty when the results return, ...

Tips for displaying real-time data and potentially selecting alternative options from the dropdown menu

Is there a way to display the currently selected option from a dropdown list, and then have the rest of the options appear when the list is expanded? Currently, my dropdown list only shows the available elements that I can choose from. HTML: < ...

Adjusting Classes in JavaScript with jQuery

I need to create a feature that changes the state of a button from active to inactive based on user input, using Bootstrap. Ultimately, I am working towards finding an intuitive way to validate form input so that the submit button can be pressed for PHP pr ...

Check input validations in Vue.js when a field loses focus

So I've created a table with multiple tr elements generated using a v-for loop The code snippet looks like this: <tr v-for="(item, index) in documentItems" :key="item.id" class="border-b border-l border-r border-black text ...

Ways to delete a class if it currently exists?

Is there a way to manage multiple toggle classes within a single div? It can be frustrating when clicking the maximize or close button triggers the minimize function as well. How can this situation be addressed? Is there a way to manage multiple toggle cl ...

ReactJS state not being updated due to a nested Axios call

Attempting to fetch data from nested axios calls, successfully retrieving responses from both calls. Struggling to update the prize_pool value within the second axios call. Any assistance would be greatly appreciated. getAllLeague() { axios.get(BA ...

Is there a method similar to insertBefore that works with arrays and/or HTMLCollections?

Is there a vanilla JavaScript or jQuery function that works like Node.insertBefore(), but for arrays and/or HTMLCollections? An example of what I'm looking for: var list = document.getElementsByClassName("stuff"); var nodeToMove = list[0]; var other ...

To properly format the date value from the ngModel in Angular before sending it to the payload, I require the date to be in the format

When working with Angular 9, I am facing an issue where I need to format and send my date in a specific way within the payload. Currently, the code is sending the date in this format: otgStartDate: 2021-07-20T09:56:39.000Z, but I actually want it to be for ...

Is the 404 page being utilized as a fallback for AJAX requests?

I am looking to create a one-page website that utilizes history.pushstate to modify the URL. My plan involves having only one HTML file for the site, which would be the 404 error page. This setup would redirect users to that page regardless of the URL they ...

Sequential execution of multiple useState updates when an update triggers a re-render

Can you explain why the function setPeople is being executed after setFirstName, setEmail, and after the event handler has been exited? const [firstName, setFirstName] = useState(''); const [email, setEmail] = useState(''); const [peopl ...

Trigger the jQuery function once the external URL loaded via AJAX is fully loaded

Currently, I am in the process of developing a hybrid mobile app for Android and I am relatively new to this technology. I have two functions in jQuery, A and B. Function A is responsible for making an AJAX request to retrieve data from 4 external PHP fi ...

The JavaScript setTimeout function not triggering repetitively for 10 instances

I'm facing an issue with a JavaScript/jQuery function that is designed to call itself multiple times if there is no available data. This is determined by making a web service call. However, the logging inside the web service indicates that it is only ...

What is the best way to store user input in local storage using Vue.js?

Following the official Vue.js site, I have been trying to implement Framework 7. However, when using an input field, [object InputEvent] is displayed both when typing text and attempting to save it. Is there a way to store a name in local storage and have ...

Restrict the number of rows in a CSS grid

Hello there, I am in the process of creating an image gallery using CSS grid. Specifically, my goal is to initially show just one row of images and then allow users to click a "Show more" button to reveal additional images. You can see my progress here: ...

What causes the unexpected behavior of JQuery's .animate() function?

I am currently working on a project that involves creating a div element for the purpose of dragging and dropping files. My goal is to have the height of the div increase when a file is dragged into it, and decrease when the file is dragged out. To achiev ...

Creating a self-chaining function in JavaScript: A guide

Currently, my goal is to create an Array.prototype function called union( array_to_union ), and then utilize it in the following manner: var a = [1,2,3]; a.union([2,3,4]).union([1,3,4]) ...... I am aiming for the outcome to be the union of these arrays. ...