Search code examples
reactjsanimationcss-transitionsrefgsap

react animation with gsap without react-transition-group and ref


I have a question with GSAP and react, as I read from some tutorials, they all use react-transition-group and also many of them use ref as an alternative selector for GSAP how ever, if I use ref in my case, the whole page will be animated, I just want a single element to animate so I use id selector, and it works totally fine like this

import React from 'react';
import { TweenMax } from 'gsap';
import uuid from 'uuid';
import '../styles/homePage.css';

class HomePage extends React.Component{

    startAnimation=(pic)=>{
        TweenMax.from(`#${pic.id}`, 1, {
            opacity: 0,
            x: -100,
            y: -100
        });
    }

    render(){
        const PicsNum = 15;
        let pics = [];
        let pic = {};
        for (let i = 5; i <= PicsNum; i++) {
            const picPath = `/pictures/testingPics/${i}.jpg`
            pic={id:`a${uuid()}`, picPath}
            pics.push(pic)
        }
        const renderPics = pics.map((p, i) => (
            <div
                key={i}
                className='img-container'
            >
                <img src={p.picPath} className='pic' id={p.id}/>
                <button onClick={()=>{this.startAnimation(p)}}>click</button>
            </div>
        ))
        return (
            <div className='pics'>
                {renderPics}
            </div>
        )
    }
}

export default HomePage;

can someone please tell me why should I use react-transition-group and what can go wrong if I want to use animation without it like I am doing? thank you very much


Solution

  • So, what you are doing here is absolutely fine for simple animations. It's only when your logic and animations start becoming more complicated that you may find it has downsides.

    The main problem you may encounter as the complexity of your logic / animation increases is that you actually are now using two different libraries to target the dom. React wants to be completely in control of the dom so it can do its thing. GSAP however also is now looking for an element in the dom and controlling it's state, and react doesn't know about so now things might get out of sync. React might re-render that component, resetting your opacity to 1, when the user has already triggered the fade out.

    React-transition-group can be a useful tool in simplifying working with animating components in and out, but it is not the only way to do it or the be all and end all of react animation, so don't feel like you have to use it. Just maybe look into the ways in which is simplifies the code you have to write for every component you want to animate in or out. (It gives you specific lifestyles for animating in and out, and a callback to remove the component post animation, which is the bulk of the boilerplate for component transitions).

    In the case of the first issue I mentioned Transition-group is useful here because all your animation code is wrapped within the helpers it provides, so react knows: 1)Your animating... don't do anything till you've finished... 2)now you've finished and I'm back in control.

    But there are other options outside of transition group to deal with this dichotomy of dom control:

    You can try to be super smart and declarative about it... use refs to access the elements and pass them to gsap animations that are triggered and controlled by state/props.

    But there are brilliant libraries that will take all the hassle out of worrying about state and animation and things like https://github.com/azazdeaz/react-gsap-enhancer

    This is a wonderful higher order component that just makes sure any changes that gsap makes to the elements are noticed and preserved across react re-rendering and state changes.

    Honestly it's a bit magic, and makes working with react and GSAP an absolute pleasure.

    Also to answer your question about 'Why refs' instead of the useful 'just pass a string of the ID to the gsap function':

    There isn't a right in wrong here. A ref in react will store a pointer to that Dom element in memory. Making it a convenient lookup. Its main advantage is the reference to that element will not expire upon a react re-render. If you manually select an element using GetElementById, and that Dom node is replaced by a react re-render, then your variable reference will become undefined and you'll have to call GetElementById again. GetElementById is very cheap in performance terms, it's not about performance, just avoiding the boilerplate of having to 'find' a new reference to the Dom element after every re-render.