Ehrgein Posted December 26, 2022 Share Posted December 26, 2022 Hey there! First of all, merry christmas. I'm a little new to GSAP and I've been trying to make an accordion for my portfolio. So far my code "works" but I KNOW it's EXTREMELY convoluted/messy, so I was wondering if anyone could help me 'refactor' it in some way. Or rather, show me how someone would do it properly, than kyou very much! I'm coding it on React along with GSAP. This is the layout effect that controls the animation timeline. const AnimationRef = useRef(); const ProjectRef = useRef(); const ProjectRefTwo = useRef(); const arrowAnimationRef = useRef(); const [menu, setMenu] = useState(false); useLayoutEffect(() => { let tl = gsap.timeline(); tl.from(ProjectRef.current, { height: 0, ease: Power4.easeInOut, }); const arrowbtn = document.getElementById("arrowbtn"); if (menu) { arrowbtn.addEventListener("click", () => { tl.reversed() ? tl.play() : tl.reverse(); }); } }, [menu]); const onRotate = () => { setisRotated((rotated) => !rotated); }; And here's the JSX: (BsChevronDown is a react-icons icon and IconContext Provider is just to change the colour of the arrow, the isRotated state is controlling a small animation that turns an arrow up or down depending on if the project is open or not. <div className=""> <span className="">KEEP MOVING</span> <IconContext.Provider value={{ size: "50px", color: "black" }}> <div> {menu ? ( <BsChevronDown onClick={onRotate} ref={arrowAnimationRef} id="arrowbtn" className={ isRotated ? "project-arrow-down-new" : "project-arrow-down open" } /> ) : ( <BsChevronDown onClick={() => setMenu(!menu)} className={ menu ? "project-arrow-down open ml-1 pepito11 " : "project-arrow-down ml-1 duration-300 pepito40" } /> )} </div> </IconContext.Provider> </div> <div id="projects"> {menu ? ( <div ref={ProjectRef} className="overflow-hidden"> <div>PROJECT TEXT</div> <div>PROJECT TEXT</div> <div>PROJECT TEXT</div> <div>PROJECT TEXT</div> <div>PROJECT TEXT</div> <div>PROJECT TEXT</div> <div>PROJECT TEXT</div> </div> ) : null} </div> Any help I'd greatly appreciate it. If you need any other code or anything please do let me know, I'm not used to sharing my code so I don't know what could be more useful specially when it comes to GSAP. Also, you ll see a "pepito40" class, that was just my way of identifying which arrow was getting render, it doesnt have any css or anything. Link to comment Share on other sites More sharing options...
Ehrgein Posted December 26, 2022 Author Share Posted December 26, 2022 I made a gif to show how the animation works, if it helps at all: Tha Link to comment Share on other sites More sharing options...
Rodrigo Posted December 26, 2022 Share Posted December 26, 2022 Hi @Ehrgein, welcome to the Forums and Merry Christmas! Is a bit hard for us to see/debug issues without a minimal demo. We have a few starter templates for React: https://stackblitz.com/@GreenSockLearning/collections/gsap-react-starters This one specifically deals with toggling a timeline instance: https://stackblitz.com/edit/gsap-react-basic-f48716?file=src%2FApp.js Of the code snippets you posted there are two things that caught my attention. First the fact that your layout effect hook creates and toggles the timeline at the same time. As you can see in the template, just create the timeline once in a layout effect with an empty array and then toggle it using another layout effect with the boolean dependency. Second, the Chevron conditional rendering seems odd to me. If you want to execute a different code based on one boolean, just do that in the handler, not in the JSX, since based on that conditional logic the class applied when menu is falsy will never be applied since that is rendered only when menu is falsy and the same can be applied for the isRotated boolean. I think is a bit confusing, convoluted and can lead to errors and maintenance issues down the line. Also take a look at this article: Finally we strongly recommend using GSAP Context when using GSAP in a React app: https://greensock.com/docs/v3/GSAP/gsap.context() Let us know if you have more questions and remember to add a minimal demo. Happy Tweening! 1 Link to comment Share on other sites More sharing options...
Ehrgein Posted December 26, 2022 Author Share Posted December 26, 2022 Thank you so much for the explanation Rodrigo! gsap.context() definitely seems to make things easier! I didn't know about using two different useLayoutEffects, that's awesome to know! Yes, I wasn't happy AT ALL with the arrow approach, my main problem was that I was having a hard time rendering the text on the click of the arrow, and since the text was rendering conditionally with the arrow, the animation was never triggering since the falsey condition for the ternary was a null div (Hence not being able to animate since there was no ref) Thank you for the playgrounds! EDIT: I managed to make it work with a codepen like this: https://stackblitz.com/edit/gsap-react-basic-f48716-kwum8b?file=src%2FApp.js In the codepen it doesnt show, but here's the result O I'll definitely be using Context from now on. If you were to recommend me an aproach for doing this with multiple columns, would you recommend doing a timeline for each specific project? I was thinking of say : User clicks on B project while A is open, then the handler for the B one should toggle the timeline for A and the timeline for B? or is there a better approach for this? Thank you so much by the way! 1 Link to comment Share on other sites More sharing options...
Solution Rodrigo Posted December 26, 2022 Solution Share Posted December 26, 2022 Hi, Yeah, the issue here is that you should create a component for each accordion item that handles the animation of just that item. In the parent component (the one that holds all the accordion items) create a state property that you can pass as a prop to each element to check which is the active one and toggle the animations based on that. Right now I have a few other examples that I'm working on, so I can't tackle this one, but it should be pretty straight forward since the logic is quite simple. Hopefully this helps. Happy Tweening! 1 Link to comment Share on other sites More sharing options...
Ehrgein Posted December 26, 2022 Author Share Posted December 26, 2022 1 minute ago, Rodrigo said: Awesome! It does help a lot, I shouldn't have much of a problem now that I know what to do or what works. I'll make sure to give the docs a further read and keep an eye on for more updates! Thanks a lot! 1 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