Jump to content

Rodrigo last won the day on March 17 2019

Rodrigo had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by Rodrigo

  1. Hi and welcome to the GreenSock forums. It would be very helpful to see a live reduced sample in either Codepen or StackBlitz, in order to find the issue faster. What I see in your snippets everything seems to be ok, perhaps the only change I would do, in order to keep things cleaner and easier to read would be to create an instance of the animation in the componentDidMount hook and toggle it's reversed state, something like this: constructor() { super(); this.aboutSection = null; this.aboutTween = null; } componentDidMount() { // HERE x:"100%" IS A SHORTHAND FOR xPercent TweenMax.set(this.aboutSection, {x: "100%"}); this.aboutTween = TweenMax.to(this.aboutSection, .8, {x: 0, ease: Power4.easeInOut}).reversed(true); } componentDidUpdate(prepProps) { // since it's a boolean, use that to change the reverese state of the GSAP instance if (this.props.isOpenedAbout !== prepProps.isOpenedAbout) { this.aboutTween.reversed(!this.props.isOpenedAbout); } } While in this subject, also I prefer to set initial state of a DOM element or component using CSS and tween the position using GSAP, because sometimes you could see flashes of the element before the componentDidMount hook is triggered, it would be as simple as using: .about { transform: translateX(100%); } Here you can see a simplified sample for another forums thread that uses x: "100%" for the animation in a React App: Finally, since you're trying to animate complete components, which could be related to navigation controls, you could use React Router and React Transition Group to create those animations. Is not too complex, take a look at this and the samples in it to see how it can be done: https://greensock.com/react Happy Tweening!!!
  2. Hi, as @elegantseagulls mentions, performance in React is tied to the React side of the code and not how you create your GSAP animations. Resource demanding animations will create performance bottlenecks in Wordpress, Joomla, React, Angular, Vue, etc. same thing on the other side of the coin, a React app with poor performance does not depends on the animation side of it, regardless of the tool you use for that. The mantra around here is: test, test, test and then test again. So just jump into it and create your app and see how it goes. If you run into some issues, post back and we'll help you through. Happy Tweening!!!
  3. No worries, happens to everyone. Happy Tweening!!!
  4. Hi, As mentioned before this is related to whether or not you have access to the DOM node in the component you're using, and if the creators of that component, actually expose the ref to the public. This is up to each component creator and if you want you can ask them to implement that, otherwise you have to do it yourself. Read from the link including the Callback Refs part (check the second snippet in that section as well): https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components Here's a simple example of that particular pattern, which is the simplest way to pass a reference to the parent (when is actually needed), but as I said, this requires for you to control the component: https://stackblitz.com/edit/react-jtfvqy?file=index.js Finally an alternative (not an elegant one though) is to wrap each <HeroBullet /> in a <div> and use the ref on the div and tween those, but this could break the component's layout. Happy Tweening!!
  5. Hi and welcome to the GreenSock forums!! For what I can see there are two things that are getting my attention. The first one is the return statement in the ref method in your JSX. That's not needed, all you have to do is update the instance reference wih the DOM node. The second thing that gets my attention is the error you're reporting since, at least in the snippet you posted, I don't see offsetWidth anywhere. If you could create a reduced case sample in either codepen or stackblitz, it'd help to pinpoint the issue faster, because the error you're reporting doesn't add up to the code you're posting. Finally a few weeks ago a getting started with GSAP and React article was released here in the GreenSock blog, take a look at it and to the samples in order to get a better grasp of how you can create GSAP animations in a React app.
  6. Hi, Indeed you need to find a way that the creators of the components give in order to reach into the component and get the DOM node. In this case Styled Components do allow the use if innerRef as @y4ure mentions. Here is an issue on the repo about it with some sample snippet: https://github.com/styled-components/styled-components/issues/1151 Try this and if you keep having issues, create a stackblitz or codepen sample to get a better look at the problem. I remember using Ant Design for a project and ultimately we had to bake our own version of some components in order to expose the DOM nodes when needed. As mentioned before, this all depends if the creators of the libraries allow users access to the DOM nodes of their components. Some do and some don't for security reasons, but that's outside the scope of this thread. Personally I've never worked with this library, I'm an old fashion guy that writes it's own SCSS files for the styles and uses class declarations in my components, but perhaps that comes with being over 40 Happy Tweening!!! PS: thanks for the kind words about the article
  7. Well, Jack beat me to it Here's the reason: Happy Tweening!!
  8. Note: This page was created for GSAP version 2. We have since released GSAP 3 with many improvements. While it is backward compatible with most GSAP 2 features, some parts may need to be updated to work properly. Please see the GSAP 3 release notes for details. A guest post from Rodrigo Hernando, a talented animator/developer who has years of experience solving animation challenges. Rodrigo is a seasoned React developer and he was one of our first moderators, serving the GreenSock community since 2011 with his expert help and friendly charm. Preface This guide assumes a basic knowledge of both the GreenSock Animation Platform (GSAP) and React, as well as some common tools used to develop a React app. As GSAP becomes the de-facto standard for creating rich animations and UI's on the web, developers must learn how to integrate it with other tools like React which has become popular because it allows developers to write their apps in a modular, declarative and re-usable fashion. As a moderator in the GreenSock forums, I've noticed that there are a few common hurdles to getting the two working together seamlessly, like referencing the DOM element appropriately, doing things The React Way, etc. which is why I'm writing this article. We won't delve into how a React app should be structured since our focus is on using GSAP, but the techniques used throughout this guide follow the official guidelines and have been reviewed by maintainers of the React Transition Group tool. We'll start simple and get more complex toward the end. How GSAP Works GSAP basically updates numeric properties of an object many times per second which creates the illusion of animation. For DOM elements, GSAP updates the the inline style properties. const myElement = document.getElementById("my-element"); TweenLite.to(myElement, 1, {width: 100, backgroundColor: "red"}); As you can see this means that we need access to the actual DOM node rendered in the document in order to pass it to the TweenLite.to() method. How React Works Explaining how React works is beyond the scope of this article, but let's focus on how React gets the JSX code we write and puts that in the DOM. <div className="my-class"> Some content here </div> With React, we normally don't pass an id attribute to the element because we use a declarative way to access methods, instances, props and state. It's through the component's (or the application's) state that we can change how things are represented in the DOM. There's no direct DOM manipulation, so typically there's no need to actually access the DOM. The React team has given developers ways to access the DOM nodes when needed, and the API changed a bit over the years as React matured. At this time (September, 2018) the latest version of React (16.4.2) allows developers to use Refs to access the DOM nodes. In this guide we'll mainly use the Callback Refs to create a reference to the DOM node and then feed it into GSAP animations because it's much faster for GSAP to directly manipulate properties rather than funneling them through React's state machine. Creating Our First Animation We'll use the ref to access the DOM node and the componentDidMount() lifecycle method of the component to create our first animation, because this will guarantee that the node has been added to the DOM tree and is ready to be passed into a GSAP animation. class MyComponent extends Component { constructor(props){ super(props); // reference to the DOM node this.myElement = null; // reference to the animation this.myTween = null; } componentDidMount(){ // use the node ref to create the animation this.myTween = TweenLite.to(this.myElement, 1, {x: 100, y: 100}); } render(){ return <div ref={div => this.myElement = div} />; } } Not that difficult, right? Let's go through the code so we can understand what is happening. First when we create an instance of this class, two properties are added to it: myElement and myTween, but both are equal to null. Why? Because at this point the node has not been added to the DOM tree and if we try to pass this node to a GSAP animation, we'll get an error indicating that GSAP cannot tween a null target. After the new instance has been initialized, the render() method runs. In the render method we're using the ref attribute that is basically a function that has a single parameter – the DOM node being added to the DOM tree. At this point we update the reference to the DOM node created in the class constructor. After that, this reference is no longer null and can be used anywhere we need it in our component. Finally, the componentDidMount() method runs and updates the reference to myTween with a TweenLite tween whose target is the internal reference to the DOM node that should animate. Simple, elegant and very React-way of us! It is worth mentioning that we could have created a one-run-animation by not creating a reference to the TweenLite tween in the constructor method. We could have just created a tween in the componentDidMount method and it would run immediately, like this: componentDidMount(){ TweenLite.to(this.myElement, 1, {x: 100, y: 100}); } The main benefit of storing a TweenLite tween as a reference in the component, is that this pattern allows us to use any of the methods GSAP has to offer like: play(), pause(), reverse(), restart(), seek(), change the speed (timeScale), etc., to get full control of the animations. Also this approach allows us to create any GSAP animation (TweenLite, TweenMax, TimelineLite, etc.) in the constructor. For example, we could use a timeline in order to create a complex animation: constructor(props){ super(props); this.myElement = null; this.myTween = TimelineLite({paused: true}); } componentDidMount(){ this.myTween .to(this.myElement, 0.5, {x: 100}) .to(this.myElement, 0.5, {y: 100, rotation: 180}) .play(); } With this approach we create a paused Timeline in the constructor and add the individual tweens using the shorthand methods. Since the Timeline was paused initially, we play it after adding all the tweens to it. We could also leave it paused and control it somewhere else in our app. The following example shows this technique: Simple Tween Demo Animating a Group of Elements One of the perks of using React is that allows us to add a group of elements using the array.map() method, which reduces the amount of HTML we have to write. This also can help us when creating an animation for all those elements. Let's say that you want to animate a group of elements onto the screen in a staggered fashion. It's simple: constructor(props){ super(props); this.myTween = new TimelineLite({paused: true}); this.myElements = []; } componentDidMount(){ this.myTween.staggerTo(this.myElements, 0.5, {y: 0, autoAlpha: 1}, 0.1); } render(){ return <div> <ul> {elementsArray.map((element, index) => <li key={element.id} ref={li => this.myElements[index] = li} > {element.name} </li>)} </ul> </div>; } This looks a bit more complex but we're using the same pattern to access each DOM node. The only difference is that instead of using a single reference for each element, we add each element to an array. In the componentDidMount() method we use TimelineLite.staggerTo() and GSAP does its magic to create a staggered animation! Multiple Elements Demo Creating a Complex Sequence We won't always get all the elements in an array so sometimes we might need to create a complex animation using different elements. Just like in the first example we store a reference in the constructor for each element and create our timeline in the componentDidMount() method: Timeline Sequence Demo Note how in this example we use a combination of methods. Most of the elements are stored as a an instance property using this.element = null, but also we're adding a group of elements using an array.map(). Instead of using the map() callback to create tweens in the timeline (which is completely possible), we're adding them to an array that is passed in the staggerFrom() method to create the stagger effect. Animating Via State The most commonly used pattern to update a React app is through changing the state of its components. So it's easy to control when and how elements are animated based on the app state. It's not very difficult to listen to state changes and control a GSAP animation depending on state, using the componentDidUpdate() lifecycle method. Basically we compare the value of a state property before the update and after the update, and control the animation accordingly. componentDidUpdate(prevProps, prevState) { if (prevState.play !== this.state.play) { this.myTween.play(); } } Control Through State Demo In this example we compare the value of different state properties (one for each control method implemented in the component) to control the animation as those values are updated. It's important to notice that this example is a bit convoluted for doing something that can be achieved by calling a method directly in an event handler (such as onClick). The main idea is to show the proper way of controlling things through the state. A cleaner and simpler way to control an animation is by passing a prop from a parent component or through an app state store such as Redux or MobX. This modal samples does exactly that: // parent component <ModalComponent visible={this.state.modalVisible} close={this.setModalVisible.bind(null, false)} /> // ModalComponent constructor(props){ super(props); this.modalTween = new TimelineLite({ paused: true }); } componentDidMount() { this.modalTween .to(this.modalWrap, 0.01, { autoAlpha: 1 }) .to(this.modalDialog, 0.25, { y: 50, autoAlpha: 1 }, 0) .reversed(true) .paused(false); } componentDidUpdate(){ this.modalTween.reversed(!this.props.visible); } As you can see the modal animation is controlled by updating the visible prop passed by its parent, as well as a close method passed as a prop. This code is far simpler and reduces the chance of error. State Modal Demo Using React Transition Group React Transition Group(RTG) is a great tool that allows another level of control when animating an element in a React app. This is referred to as the capacity to mount and unmount either the element being animated or an entire component. This might not seem like much when animating a single image or a div, but this could mean a significant performance enhancement in our app in some cases. SIMPLE TRANSITION DEMO In this example the <Transition> component wraps the element we want to animate. This element remains unmounted while it's show prop is false. When the value changes to true, it is mounted and then the animation starts. Then when the prop is set to false again, another animation starts and when this is completed it can also use the <Transition> component to wrap the entire component. RTG also provides the <TransitionGroup> component, which allows us to control a group of <Transition> components, in the same way a single <Transition> component allows to control the mounting and unmounting of a component. This is a good alternative for animating dynamic lists that could have elements added and/or removed, or lists based on data filtering. Transition Group Demo <Transition timeout={1000} mountOnEnter unmountOnExit in={show} addEndListener={(node, done) => { TweenLite.to(node, 0.35, { y: 0, autoAlpha: show ? 1 : 0, onComplete: done, delay: !show ? 0 : card.init ? props.index * 0.15 : 0 }); }} > In this example we use the addEndListener() callback from the <Transition> component. This gives us two parameters, the node element being added in the DOM tree and the done callback, which allows to control the inner state of the <Transition> component as the element is mounted and unmounted. The entire animation is controlled by the in prop, which triggers the addEndListener() and ultimately the animation. You may notice that we're not creating two different animations for the enter/exit state of the component. We create a single animation that uses the same DOM node and the same properties. By doing this, GSAP's overwrite manager kills any existing animation affecting the same element and properties, giving us a seamless transition between the enter and exit animations. Finally, using RTG allows us for a more fine-grained code, because we can use all the event callbacks provided by GSAP (onStart, onUpdate, onComplete, onReverse, onReverseComplete) to run all the code we want, before calling the done callback (is extremely important to notify that the animation has completed). Animating Route Changes Routing is one of the most common scenarios in a React app. Route changes in a React app means that an entirely different view is rendered depending on the path in the browser's address bar which is the most common pattern to render a completely different component in a route change. Obviously animating those changes gives a very professional look and feel to our React apps. Rendering a new component based on a route change means that the component of the previous route is unmounted and the one for the next route is mounted. We already covered animating components animations tied to mount/unmount using the <Transition> component from RTG, so this is a very good option to animate route changes. <BrowserRouter> <div> <Route path="/" exact> { ({ match }) => <Home show={match !== null} /> } </Route> <Route path="/services"> { ({ match }) => <Services show={match !== null} /> } </Route> <Route path="/contact"> { ({ match }) => <Contact show={match !== null} /> } </Route> </div> </BrowserRouter> This main component uses React Router's <BrowserRouter> and <Route> and checks the match object passed as a prop to every <Route> component, while returning the component that should be rendered for each URL. Also we pass the show property to each component, in the same way we did in the transition example. <Transition unmountOnExit in={props.show} timeout={1000} onEnter={node => TweenLite.set(node, startState)} addEndListener={ (node, done) => { TweenLite.to(node, 0.5, { autoAlpha: props.show ? 1 : 0, y: props.show ? 0 : 50, onComplete: done }); }} > As you can see, the code is basically the same used to animate a single component; the only difference is that now we have two animations happening in different components at the same time. Route Animation Demo It's worth noting that the animations used in this example are quite simple but you can use any type of animation even complex, nested animations. As you can see by now, using GSAP and React can play together nicely. With all the tools and plugins GSAP has to offer the sky is the limit for creating compelling and amazing React applications! FAQ What is this "Virtual DOM" thing, that is referred so much when it comes to React Apps?. Can GSAP work with this virtual dom? The Virtual DOM is what React uses to update the DOM in a fast and efficient way. In order to learn more about it check this article and the React Docs. GSAP can't work with the virtual DOM because the elements in the Virtual DOM are not exactly DOM nodes per-se. I often read about the declarative nature of React. Does that affect how we use GSAP in a React APP? Yes. React works by updating the rendered DOM through changes in the App state, so when creating an animation using GSAP, instead of reaching out directly to the DOM, like in most other cases, we need to wait for those changes in the app state and the DOM to be rendered, in order to use the current representation of the app state and create the animation. To learn more about how declarative and imperative code work read this article. In the second sample I see this code in the ref callback ref={div => this.cards = div}. Why is the index being used instead of just pushing the element in the array? The reason for that is that every time a React component is re-rendered, the render method is executed, but the original instance remains unchanged. The array used to create the animation is created in the component's constructor. The GSAP animation (a TimelineLite) is created in the componentDidMount hook. These two elements are created just once in the App's lifecycle, while the render method is executed on every re-render. Therefore if we push the elements to the array on every re-render, even though the Timeline instance won't change, the array will get bigger and bigger every time the component is re-rendered. This could cause a memory issue, especially for large collections. In the guide one of the samples triggers animations via the state of a component or the app. Is it possible to update the state of the component/app using GSAP? Absolutely! All you have to do is use one of the many callback events GSAP has to offer. The only precaution is to be aware of infinite loops. That is if an animation is started on the render method of a component and a callback from that animation updates the state of the component then that will trigger a re-render, which will start the animation again. You can check this simple example of how that can be done. Is it possible to trigger a route change using GSAP? It is possible using React Router's API. Although is not recommended because using React Router's API directly will prevent triggering the route change animations when using the browser's back and forward buttons. However, using React Transition Group with GSAP does trigger the route change animations with the native navigation methods. Can I use other GSAP plugins and tools in a React App? This guide shows only TweenMax, Timeline and the CSS Plugin? Yes, any GSAP tool or plugin you want can be used in a React app. Just be sure to follow the same patterns and guidelines from this article and you'll be fine. I tried the code in the guide and samples, but it doesn't work. What can i do? Head to the GreenSock forums where all your questions will be answered as fast as possible. I want to contribute or post an issue to this guide. Where can I do that? Even though this guide was reviewed by GreenSock and React experts, perhaps something might have slipped away, or with time and new versions, some things should or could be done differently. For those cases please head to this GitHub Repo and inform any issues or create a Pull Request with the changes you think should be added. New to GSAP? Check out the Getting Started Guide. Got questions? Head over to the GreenSock forums where there's a fantastic community of animators. Acknowledgments I'd like to thank the three developers that took time from their work and lives to review this guide as well as the samples in it. I couldn't have done this without their help and valuable input. Please be sure to follow them: Xiaoyan Wang: A very talented React developer. While Xiaoyan doesn't have a very active social life (twitter, facebook, etc), you can follow what he does in GitHub. Jason Quense: One of the maintainers of React Transition Group and part of the React Bootstrap Team. Jason also collaborates in many other React-related projects. Check Jason's GitHub profile for more info. Matija Marohnić: The most active contributor and maintainer of React Transition Group and Part of the Yeoman Team. Matija also contributes in a lot of React-related projects as well as many other open source software. Be sure to follow Matija in GitHub and Twitter.
  9. Hi, One alternative that I can think of is using Adobe After Effects with nexrender and the solution by Blake to create an MP4 video. I created a small Node app that was used in a client machine (no server, but you can easily deploy it) that basically was getting images from an AWS bucket. The idea was to create a project with two parameters, a bucket for storing the images and a flag to start the rendering process, so after all the images were uploaded the user set the state of the project from upload to render and the Node app listened to that state change, downloaded the images, and started the nexrender process. When that was completed it uploaded the video generated from After Effects. Here's the nexrender repo https://github.com/inlife/nexrender And here's a ready-bake boilerplate (this is the one used in the project I worked on): https://github.com/inlife/nexrender-boilerplate Unfortunately because of an NDA I can't share any of that code, but the nexrender setup is quite simple actually and they have some pretty good docs and the Node part of this is quite simple as well. The tricky part (that I didn't do actually) is the configuration of the AE file for creating the resulting video with the images. But is one way to automatize the whole process. Although is worth mentioning that the videos that the app I worked on, weren't based on frames, they were just some fade in/out of images with a background sound and some other effects, but again I worked only on the Node side of this so I couldn't tell you how to work on that part, so you'll have to rely on what the guys in nexrender could tell you. But perhaps there is a way to turn a bunch of frames into a video using AE. Hope this helps a little.
  10. Hi, You're not missing anything stupid at all. You're just the latest victim of the las update by React (starting in versions 16.5.x) that causes an issue when using GSAP's Draggable. Just add dragClickables: true in your Draggable instance and it will work: export default class App extends React.Component { componentDidMount() { this.draggable = new Draggable(this.draggableRef, { type: "x,y", dragClickables: True }); } render() { return ( <div ref={ref => {this.draggableRef = ref;}} style={{width: 100, height: 100, background: "#f00"}} /> ); } } Another alternative is roll-back to React 16.4.2 For more details and information about this issue, please refer to this post: And this issue in React's repo: https://github.com/facebook/react/issues/13654 The next release of GSAP will have this fixed. Happy Tweening!!!
  11. Hey @b0dg4n, actually the docs currently have a specific part for NPM usage that also covers how to include bonus GreenSock club's plugins: https://greensock.com/docs/NPMUsage Around the middle of the page is mentioned how to include the bonus plugins and tools. Happy Tweening!!!
  12. But Jack, that would mean that by default all the elements that, since the drag clickable bool was introduced, weren't elegible for being draggable will be now by default, right?, like buttons, inputs, textareas, etc?. Sure thing there isn't a lot of samples of buttons and inputs being used as Draggable targets, but still it changes the way things were done up to now. My two cents is that adding that workaround for React users, is not a big deal, you could add an indication in the Draggable docs. Although I don't know the ratio between users creating Draggable instances out of buttons vs Draggable usage in React. Personally I've used it just once in quite a few React projects, but that's me. If you think this is the best way to go for GSAP, I agree with it. Happy Tweening!!
  13. Mhh... Honestly I don't know, I'll ask about that specific function. In the inspector comes as a no-op function in the root element. I opened an issue in React's repo. I'll post any updates in that matter. Happy Tweening!!! --- EDIT To keep everyone in the loop, this is the issue in React's repo: https://github.com/facebook/react/issues/13654 We got a very fast answer from Dan Abramov. Dan explains that this was done to solve an issue on iOS and that is not going away, even further the trend may continue with other events, but that is not pertinent to this discussion. Dan labeled the issue as discussion, which means they are listening to the community, so if anyone is interested in participating, please do.
  14. @GreenSock, Jack, indeed the issue is not bundling-related, here's a codepen using the React files directly without create react app and still the same: In the mean time I can create an issue on React's repo so they can track this as well. Best, Rodrigo.
  15. Mhh... seems like a bug in the version of react Blake's sandbox uses version 16.4.2 and yours is using perhaps 16.5.1? This sandbox is using 16.5.1 and nothing, nada: https://codesandbox.io/s/jrkbkxeqy Same in stackblitz: https://react-wxzf4q.stackblitz.io/ This might require digging up and creating an issue on React's repo, because the pointer events are triggering but the onDragStart event is not being triggered, so basically this is not sending the amount of pixels the pointer has moved. Also it doesn't work with Draggable type: "x, y" neither. What's odd is that this sample (which is an extreme simplification of how Draggable works) works fine: https://codesandbox.io/s/xdjy28xov We'll summon our master @GreenSock in order to find what's going on here, so stay tuned. In the mean time my recommendation is to drop the React and React DOM dependencies to 16.4.2
  16. Indeed... the blunder has been corrected master!!!
  17. Hi, Actually this has nothing to do with React (how about that React is not the culprit, who would have suspected?? ) but with the fact that the ScrollTo Plugin doesn't work with relative values like a regular tween using the CSS Plugin, that's why the first code you posted doesn't work (it actually doesn't work with or without React) and the second snippet does. What you can do is access the scrollLeft property of the target element and add the increment value to that: TweenMax.to(content, 0.5, { scrollTo: { x: (content.scrollLeft + incrementNumber) } }); That should do the trick. Let us know how that works. Happy Tweening!!!
  18. Ahh yeah the parenthesis, sorry SVG is not my thing. Unlucky you @PointC didn't answer this question , but glad to hear you were able to solve it Happy Tweening!!!
  19. Hi Gilbert, I'll assume that the clipPathId passed in the components props is the url you want to add, right? If that's the case you can use template literals a feature from ES2015: <g ref={(el) => { this.clipPathReveal = el; }} clipPath={`url#${this.props.clipPathId}`}> If this is not what you're after, please let us know how the specific clip url is being passed. Happy Tweening!!!
  20. @mdvoy Is not necessary to go through all that code to get the dom node from react, specially if you're using React Transition Group (RTG). The onEnter, onExit and addEndListener events from RTG already give you access to the DOM node you're animating, which is the one wrapped byt the <Transition> tag. Check them in their API docs here. All you have to do is call a function in one of those methods to trigger an animation when a route changes: <Transition key={props.location.pathname} timeout={500} mountOnEnter={true} unmountOnExit={true} onEnter={node => { // set the position and properties of the entering element TweenLite.set(node, { position: "fixed", x: 100, autoAlpha: 0, width: targetWidth }); // animate in the element TweenLite.to(node, 0.5, { autoAlpha: 1, x: 0, onComplete: completeCall, onCompleteParams: [node] }); }} onExit={node => { // animate out the element TweenLite.to(node, 0.5, { position: "fixed", opacity: 0, x: -100 }); }} // on exit end > As you can see is not that hard. You can check RTG docs and see all the options you have to work with. Also take a look at this discussion in RTG GitHub repo, regarding page transitions with React Router: https://github.com/reactjs/react-transition-group/issues/136 Take a good look at this sample by Matija Marohnić (who is one of the main maintainers of RTG) which is quite simple an works great: https://github.com/reactjs/react-transition-group/issues/136#issuecomment-406626669 As personal advice try to avoid, specially if you're not very experienced, the code from React Router's samples. It doesn't have any comments so is not that easy to follow and understand. Finally if you can create a live reduced sample in codesandbox or stackblitz, in order to get a better look at what you're doing, it would be great. Happy Tweening!!!
  21. @n00banim8r you're welcome. Your code looks quite fine and the filter transitions are smooth, good job. As you mention the React GSAP enhancer is quite outdated and I don't see (or heard of) any intentions in getting it up-to-date with the latest versions of GSAP and React, so I wouldn't recommend it's use. Also as you already saw is not needed when you use Transition Group. So my advice is that when you're animating components being mounted or unmounted, stick with GSAP and React Transition Group and everything should work ok. Also RTG has very good docs for it's API which is very simple actually so is a great tool to use with GSAP. Happy Tweening!!!
  22. Hi and welcome to the GreenSock forums. The first thing you're missing, that has nothing to do with GSAP, is the fact that you're not passing the in property to the components or DOM nodes you want to animate. That's the most important thing a <Transition> tag needs to work. Second, you don't need to wrap every <Transition> inside a <TransitionGroup> tag. Use a <TransitionGroup> tag outside your array.map() helper to add each <Transition> to it: generateCards = () => this.state.items.map(item => ( <Card key={dasherize(item.name.toLowerCase())} {...item} /> )); // in the render method <div className="app-container"> <TransitionGroup> {this.generateCards()} </TransitionGroup> </div> Then get rid of the componentWillReceiveProps lifecycle method because is being deprecated and is considered unsafe: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops Also this methods you have don't exist in the lifecycle of a component: componentWillEnter and componentWillLeave. By adding them in your code you're creating them and adding them to the component's instance, but nothing more, those are not being executed unless you do it manually, so is best to remove them. Here is the documentation regarding components and their lifecycle: https://reactjs.org/docs/react-component.html Finally this sample is somehow similar to what you're doing (without the filtering of course, but that shouldn't be too complicated to achieve): https://codesandbox.io/s/7lp1q8wba The relevant code starts in line 100, so don't pay too much attention to the code above that line. From line 100 below is what you need to check. Also take a look at the API of react transition group: https://reactcommunity.org/react-transition-group/transition http://reactcommunity.org/react-transition-group/transition-group/ Happy tweening!!
  23. Hi and welcome to the GreenSock forums. As you mention GSAP keeps reference to the DOM nodes so if their aren't in the DOM tree you don't get the cannot tween a null value error. What you could try is run some code in componentWillUnmount in order to check if those nodes are part of a GSAP instance using getTweensOf(). Also since you're using RTG on an entire component, you could create an association between a component and a specific GSAP instance since the component is not in the DOM tree, you could prevent that specific timeline from playing. Another scenario is that some DOM elements of the component being animated might not be present at some point during the component's lifecycle after the GSAP instance has been created?. In that case get the tweens of the timeline and check the target of those to see if they are present in the DOM tree or not. IN this regard you're storing an internal reference in the component's instance using the ref callback. When/if the node is not rendered, that reference is updated or not?. Perhaps you can check that and update everything after a component update. A more detailed information of what is happening React-wise in your app and how that creates the issue would be nice. Happy Tweening!!!