mabdelra Posted October 27, 2022 Share Posted October 27, 2022 Hi guys im trying to animate an FAQ component in react the animation works in my localhost however when i initiate a build and host it on netlify it no longer works and the faq stays in its expanded state, im using tailwindcss for the styling if you want to copy the code directly, sorry if this is messy im still unfamiliar with using codepen to provide a demo especially for react since im only starting to learn it now 😕. import { useEffect } from "react" import { useRef } from "react" import gsap from "gsap" import SplitText from 'gsap/SplitText' gsap.registerPlugin(gsap, SplitText) const questions = [ { title: 'question?', answer: ' Lorem ipsum dolor sit amet consectetur adipisicing elit. Nobis modi qui non ullam hic maxime veritatis et nemo eius nihil eos rem, asperiores nulla aspernatur quisquam eaque officiis atque odit?', id: 1, }, { title: 'question?', answer: ' Lorem ipsum dolor sit amet consectetur adipisicing elit. Nobis modi qui non ullam hic maxime veritatis et nemo eius nihil eos rem, asperiores nulla aspernatur quisquam eaque officiis atque odit?', id: 2, }, { title: 'question?', answer: ' Lorem ipsum dolor sit amet consectetur adipisicing elit. Nobis modi qui non ullam hic maxime veritatis et nemo eius nihil eos rem, asperiores nulla aspernatur quisquam eaque officiis atque odit?', id: 3, }, { title: 'question?', answer: ' Lorem ipsum dolor sit amet consectetur adipisicing elit. Nobis modi qui non ullam hic maxime veritatis et nemo eius nihil eos rem, asperiores nulla aspernatur quisquam eaque officiis atque odit?', id: 4, }, ] const Faq = () => { const app = useRef([]) useEffect(() => { return () => { let active let faq = document.querySelectorAll('.question'); faq.forEach((element) => { let answer = element.querySelector('.answer') let animation = gsap.timeline({}) .to(answer, { opacity: 0, visibility: 'invisible', duration: 0.05 }) .to(answer, { height: 0, duration: 0.4, ease: 'power3.inOut' },'<+100%') element.animation = animation element.addEventListener('click', function(){ if(active){ active.animation.play() // reverse (close) active element's animation } element.animation.reverse() // play (open) the clicked element's animation active = element }) }) } }) return( questions.map(item => { const {title,id, answer} = item; return ( <div className="question" key={id} ref={(index, element) => app.current.splice(index, 1, element).push(element)}> <div key={id} className='mb-5 border text-white border-line-rule hover:border-btn-clr hover:text-btn-hvr hover:transition-[350ms] hover:bg-btn-bg rounded-xl py-4 px-4 flex flex-col items-center justify-between'> <button className='closeBtn flex py-2 justify-between items-center 2xl:text-2xl 2xl:py-2.5 w-full'> <h3>{title}</h3> <div className='close'> <svg data-accordion-icon className="w-6 h-6 shrink-0" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" ></path></svg> </div> </button> <div className='answer border-t border-line-rule'> <div className='py-5'> {answer} </div> </div> </div> </div>) }) ) } export default Faq Link to comment Share on other sites More sharing options...
GreenSock Posted October 27, 2022 Share Posted October 27, 2022 Thanks for being a Club GreenSock member! 🥳 I notice several mistakes: You're not actually doing anything in your useEffect() - you're just returning a cleanup function that has all the logic in it. You didn't use an empty dependency array for your useEffect(), so it'll get called on every render. You're not doing proper cleanup. I'd highly recommend using gsap.context() to make that easier. So it's mostly React-specific stuff. I'm not much of a React guy myself, but I'd strongly recommend reading this article: Here's a very quick CodePen that I slapped your code into in case it helps: See the Pen gOKppmm?editors=0010 by GreenSock (@GreenSock) on CodePen Good luck! 👍 Link to comment Share on other sites More sharing options...
mabdelra Posted October 28, 2022 Author Share Posted October 28, 2022 21 hours ago, GreenSock said: Thanks for being a Club GreenSock member! 🥳 I notice several mistakes: You're not actually doing anything in your useEffect() - you're just returning a cleanup function that has all the logic in it. You didn't use an empty dependency array for your useEffect(), so it'll get called on every render. You're not doing proper cleanup. I'd highly recommend using gsap.context() to make that easier. So it's mostly React-specific stuff. I'm not much of a React guy myself, but I'd strongly recommend reading this article: Here's a very quick CodePen that I slapped your code into in case it helps: 21 hours ago, GreenSock said: Good luck! 👍 Thank you so much for the fast response! i see what you mean and it works perfectly I do have one more question though, how do i go about adding another onClick event that closes the modal when its clicked for the second time? I really appreaciate how helpful you guys at Greensock are by far the best community I have ever been a part of! Link to comment Share on other sites More sharing options...
GreenSock Posted October 28, 2022 Share Posted October 28, 2022 1 hour ago, mabdelra said: I do have one more question though, how do i go about adding another onClick event that closes the modal when its clicked for the second time? There are many ways to handle that. Here's one: See the Pen JjZdaMB?editors=0010 by GreenSock (@GreenSock) on CodePen 1 hour ago, mabdelra said: I really appreciate how helpful you guys at GreenSock are by far the best community I have ever been a part of! We love hearing that. Thanks so much! 💚 Link to comment Share on other sites More sharing options...
mabdelra Posted October 29, 2022 Author Share Posted October 29, 2022 Hi Jack, Thanks again for your help! I am quite lost at the ._ notation syntax you are using in the if statements and the clean up function can you explain what that is and how come you dont need to declare the function using a const or let statement? Lastly why do we need to clean up the event listeners at the end of the context function ? Thank you so much again I really appreciate it! Link to comment Share on other sites More sharing options...
Solution GreenSock Posted October 30, 2022 Solution Share Posted October 30, 2022 6 hours ago, mabdelra said: I am quite lost at the ._ notation syntax you are using in the if statements and the clean up function can you explain what that is and how come you don't need to declare the function using a const or let statement? I'm just assigning arbitrarily-named properties to the elements themselves. Elements are just objects anyway, so you can do that. For example: let obj = {}; // create an object obj.myProperty = 100; // assign a property let el = document.querySelector("#id"); // get Element el.myProperty = 100; // assign a property I just use an underscore as a convention to indicate it's a "private" property (not to be edited by other developers). It's merely a convention. You can name it whatever you want. Omit the _ if you want. 6 hours ago, mabdelra said: Lastly why do we need to clean up the event listeners at the end of the context function ? That'll get called anytime the context gets reverted. So when your useEffect() triggers its cleanup, like maybe if the component gets unmounted/trashed. If you don't cleanup your event listeners, they could keep getting triggered but honestly that's unlikely in our scenario because the elements wouldn't be in the DOM anymore thus they wouldn't get clicked but it's just considered good practice to always remove your event listeners in the cleanup function. Does that clear things up? Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now