LucieB Posted March 28, 2020 Share Posted March 28, 2020 Hey ! I'm experimenting with React JS, and I'm wondering what is the best method to start an animation when the DOM's ready with React JS. Plus, I don't know what method is the best to target elements in React JS. I need some advices : Should I use useCallback hook, or simply the States and Refs ? Here's an example of what I did. This is very simple and minimalist. https://codesandbox.io/s/prod-river-xqvuu Actually, the animation works, but as I said I would like to know if my method looks good or not. If someone could take a look... Thanks !! Take care Lucie Link to comment Share on other sites More sharing options...
ZachSaucier Posted March 28, 2020 Share Posted March 28, 2020 Hey Lucie. You should check out our article on GSAP + React. It uses GSAP 2, but the concepts are the same: 5 hours ago, LucieB said: I would like to know if my method looks good or not Using useEffect is a fine method. It just might be a little more difficult than using classes in some cases. I'm not sure if adding the elements to the state is sufficient in all cases. It may be better to use refs for each element. I'm sure someone with more skill in React like Blake or Rodrigo will come by and comment Some notes about your use of GSAP usage: You don't need to say new before gsap.timeline() You don't need to use a timeline to do the same effects on different elements - you could use one tween with staggers instead if you'd like! Something like gsap.to(state, { autoAlpha: 1, duration: 1, stagger: 1 }); For more about staggers, check out the stagger docs page. 3 Link to comment Share on other sites More sharing options...
Rodrigo Posted March 28, 2020 Share Posted March 28, 2020 In fact using an useEffect or the corresponding componentDidMount in class components is the best way to be sure that the DOM elements do exist. Keep in mind though, that using that call inside an useEffect hook, will trigger that code every time the state or props of that component are updated, that's why is better to use an empty array as a second argument in the useEffect hook: useEffect(()=>{ // code in here }, []); // empty array ensures that the code is ran only when the component is mounted Also you don't need the useCallback hook to set the DOM elements. In fact I wouldn't recommend it, plus you're not using the hook correctly. The idea of that hook is to create and update values only when the dependencies in the array are updated. Right now you're passing an empty array. Also the constant you're creating is not being used anywhere in your code: // This constant is never used const el = useCallback(node => { if (!node) return; const myTitle = node.children[0]; const mySubtitle = node.children[1]; const myParagraph = node.children[2]; setState(state => [myTitle, mySubtitle, myParagraph]); }, []); Is better to create a unique variable for the parent node element. This code achieves the same result you're getting now: import React, { useEffect} from "react"; import { gsap } from "gsap"; import "./styles.css"; export default function App() { let parentNode = null; useEffect(() => { console.log(parentNode); gsap.set(parentNode.children, { autoAlpha: 0 }); const tl = new gsap.timeline(); tl.to(parentNode.children[0], { autoAlpha: 1, duration: 1 }); tl.to(parentNode.children[1], { autoAlpha: 1, duration: 1 }); tl.to(parentNode.children[2], { autoAlpha: 1, duration: 1 }); }, []); return ( <div className="App" ref={el => (parentNode = el)}> <h1>My Title</h1> <h2>My Subtitle</h2> <p>My paragraph</p> </div> ); } Happy Tweening!!! 6 Link to comment Share on other sites More sharing options...
LucieB Posted March 29, 2020 Author Share Posted March 29, 2020 Thanks Rodrigo and Zach for the answers! If I understand everything you said, I need to declare all my variables inside the useEffect method. But for example, if I want to add an event on click and add an animation for the same elements (autoAlpha in the title), should I need to re-write the variable (inside the event function) ? I created an other codesandbox to illustrate my question (because my english is a little bit limited, I'm sorry). Thanks again for your time. Take care, Lucie Link to comment Share on other sites More sharing options...
Rodrigo Posted March 29, 2020 Share Posted March 29, 2020 You're welcome. First there is no need nor obligation to declare variables/constants inside of useEffect, especially if you plan on using those outside the scope of the useEffect hook. If you'll use just inside the hook, sure there is no problem. In the case of this code: const disappear = () => { const title = parentNode.children[0]; // Should I re-write this variable ? gsap.to(title, { autoAlpha: 0, duration: 1 }); }; There is no need to re-declare that variable since it resides inside the disappear method, so every time that method is called that variable will be created, the GSAP instance will be created and one the animation is completed both elements will be elegible for garbage collection. If you want to animate something more than once during the lifetime of your app, then is better to create the variables/constants that you will use in the scope of the component. This sample uses that approach without any props or state update: https://codesandbox.io/s/simple-gsap-instance-toggle-xc741 If the props or state of your component will be updated at some point during it's life cycle, then you have to store the GSAP instance in the component's state: https://codesandbox.io/s/gsap-toggle-instance-with-hooks-t9uqr In these two threads you can find some explanations why the latter approach is needed: Happy Tweening!!! 4 Link to comment Share on other sites More sharing options...
LucieB Posted March 29, 2020 Author Share Posted March 29, 2020 Thanks you very much Rodrigo! 1 Link to comment Share on other sites More sharing options...
LucieB Posted April 4, 2020 Author Share Posted April 4, 2020 Hey, I met some issues with this technique. Perhaps because my Wifi connection is not excellent... When I push my website to the prod and watch it, sometimes the timeline is animating before the document is ready. I mean the animation began before all the content is loaded, specially on mobile. Even if I use a delay for the tl. So my question is : should I create a state for the timeline to resolve this problem ? Thanks a lot again, and take care! Link to comment Share on other sites More sharing options...
Rodrigo Posted April 4, 2020 Share Posted April 4, 2020 Do you have some url we can take a look at? With the information you're providing is hard to pinpoint what the issue could be and we'll be just guessing. Honestly this is quite odd. I'll assume that you're working with create react app to bundle your code, the thing about that is that it generates a single JS file with all the code for the app which should work as it did in your development environment. I assume that you're using this approach for your animation: https://codesandbox.io/s/simple-gsap-instance-toggle-xc741 One option could be that the timeline instance is not paused when you create it. Another possibility is that the app is too complex and all the rendering and painting work the browser has to do is taking too long. Have you checked the performance tab in chrome dev tools in order to see how the initial render of the site is working? This could also be a performance problem which is consistent with the fact that in mobile devices it gets worst. Also you can install React Devtools and use the profiler to see how the React part of your code is working. React Dev Tools for chrome: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=es React Devtools profiler docs: https://reactjs.org/docs/optimizing-performance.html#profiling-components-with-the-devtools-profiler Short video tutorial on using and understanding the profiler: 4 Link to comment Share on other sites More sharing options...
LucieB Posted April 12, 2020 Author Share Posted April 12, 2020 Thanks again Rodrigo! Everything's working as I want! Thanks to you! I only have a last question about targeting elements, in React for GSAP animations: Actually I only target elements that I want to animate with useRef. No problem at all. But I'm wondering if we could create some variables to store the ref path to animate the element we want. I create a new CodesandBox to illustrate my question : https://codesandbox.io/s/target-elements-in-react-gsap3-3vz98 I created an animation in useEffect, when the DOM's ready. But I also created an event listener on the button onClick. And to animate the title, or the subtitle, I need to rewrite the entire path from the ref ( eg. containerRef.current.children[0] ). So, my question is : Should I store the path in a state ? Like this : const [title, setTitle] = useState(""); useEffect(() => { setTitle(containerRef.current.children[0]); }, []); const myEvent = () => { gsap.to(title, { color: "red", duration: 1 }) } I'm sorry about all my questions. I just would like to write the cleanest code as I can. Thanks again, Rodrigo! Link to comment Share on other sites More sharing options...
Rodrigo Posted April 12, 2020 Share Posted April 12, 2020 Hey, unfortunately I'm getting a 404 error with the link for the codesandbox sample so I can't take a look at it, please check it out and see if it's still live. If you want to create a constant or variable for each element you want to animate, that's fine, no problem with it. Keep in mind though that right now you have a reference for the parent element so you can access each child using it's index. If you want to avoid that, because the index might not be fully predictable, you can use a ref for each element you want to animate and store that ref in a constant. Then you can use those to create the GSAP instances. If you check this sample you'll see that I'm creating a variable for the DOM element which is later replaced by the ref callback inside the JSX and a event handler to control the GSAP instance that is also created: https://codesandbox.io/s/simple-gsap-instance-toggle-xc741?file=/src/App.js:110-117 There is no actual need to create a ref in the component's state a simple variable should be enough even if the component's state is updated, like this sample: https://codesandbox.io/s/gsap-toggle-instance-with-hooks-t9uqr?file=/src/App.js:221-228 At the end this comes down to how comfortable you are with the code that you're writing, that the code makes sense to you and for those who could look at it in the future, so it's easy to maintain and debug. Happy Tweening!!! 2 Link to comment Share on other sites More sharing options...
LucieB Posted April 13, 2020 Author Share Posted April 13, 2020 Hey Rodrigo, I'm sorry about the 404. I thought my link was good. I recreated what i want to illustrate here. This is not about a reverse animation. I just created two different animations, and as you can see I re-write the target for animation the element (eg. container.current.children[0]). Do you think the best method is to create a state and store inside the element I want to animate differently (to not repeat myself in writing the ref children) ? I let you look at my code, if you have some time. Thanks again for your time. Take care! Lucie Link to comment Share on other sites More sharing options...
Rodrigo Posted April 13, 2020 Share Posted April 13, 2020 Well performance wise there shouldn't be a difference unless we're talking about hundreds or thousands of elements, which is not the case. As I mentioned throughout the thread, both patterns are equally valid and creating an extra variable or constant to access them shouldn't cause a problem. Perhaps the only advice would be to change it to this: useEffect(() => { const children = container.current.children; tl.from(children[0], { autoAlpha: 0, yPercent: 20, duration: 0.75 }) .from(children[1], { autoAlpha: 0, yPercent: 15, duration: 0.5 }) .from(children[2].children, { autoAlpha: 0, yPercent: 25, duration: 1, stagger: { amount: 0.75 } }) .from(children[3], { autoAlpha: 0, duration: 1 }) .play(); }, []); That's definitely a bit better to look at and it's DRY Finally I'll repeat what I said in the previous post, there is no obligation to put the reference to the DOM element in the state, that's just a personal preference, nothing more. Depends only with what approach you're more comfortable with. Happy Tweening!!! 4 1 Link to comment Share on other sites More sharing options...
LucieB Posted April 13, 2020 Author Share Posted April 13, 2020 This is perfect! Thanks for all explanations Rodrigo. And I'm sorry about all my questions... 2 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