Jump to content

Search In
  • More options...
Find results that contain...
Find results in...

Rodrigo last won the day on September 1

Rodrigo had the most liked content!


  • Content Count

  • Joined

  • Last visited

  • Days Won


Rodrigo last won the day on September 1

Rodrigo had the most liked content!

Community Reputation

2,691 Superhero

About Rodrigo

  • Rank
    Advanced Member

Contact Methods

  • Skype

Profile Information

  • Gender
  • Location
    Santiago - Chile

Recent Profile Visitors

22,745 profile views
  1. Hi and welcome to the GreenSock forums. The main issue here could be the fact that you're creating the animation when the component is mounted, but since you're working with async data, the componentDidMount event is triggered after the first render, but then the server response comes back and a new render is triggered with the updated data, but the GSAP instance is already created with other DOM elements (the ones from the first render) so that's why after the re-render generated from the server response, the actual DOM elements in the screen are not the same that GSAP has in the Timeline instance. You're pretty close to a solution though, so it won't be too hard to implement I think. Don't use the componentDidMount event to create the animation and use the componentDidUpdate to do so, keeping in mind that if your data will be updated at some point is better to stop, kill and clear the timeline after a new server response has arrived. Here is an extremely simplified version using axios to fetch some data from a dummy API: https://codesandbox.io/s/gsap-animation-react-async-data-c0017 Hopefully is enough to help. Happy Tweening!!!
  2. Actually what I meant by that is how to handle the server response, regardless of when the data actually is. The main idea is to keep the state as clean as possible. I assume that you have some sort of recursive data fetching code in your app or you're running something like Firebase that can update, on-demand, the client data whenever the server data is updated. The point of that suggestion is not limit the data you're receiving from the server, just how to filter it and keep the component's state as clean as possible once the response is in the client-side. Happy Tweening!!
  3. Hi, Unfortunately stackblitz is giving a generic error, so there is no way to actually pinpoint what and where is happening here. For mutating state, if you're using setState() then you don't have to worry about it. React is handling things for you when updating the component's state. Immutability is suggested when you use a store software such as Flux, Redux, Mobx, VueX, etc., where the dev is in charge of creating and maintaining the state. In those cases is recommended to create a new object instead of changing the current one when a state mutation happens. Although VueX does handles that for you. A few pointers though. Is not at all necessary to do all that convoluted filtering when is not needed. What I mean is that when you create the app you have all the data in the state. On top of that you filter that data in sub-sets and add all those sub-set to the state as well. Basically that creates a duplicated data set. Data filtering is not an extremely expensive process. It all depends on the amount of data, but under 500 elements it should really fast specially if the filter test is simple like your case. When the user actually wants a sub-set of the original data, create it and set it as the state property. So instead of having a bunch of state properties for all the cities and every possible sub-set, just create one that is what the user wants. More arrays in your app means more memory, more CPU to handle all of them, which leads to more battery use in devices and so on. Right now you're using onTheMap for the data set shown in the app, keep using just that when filtering the data. My best guess is that the animation is not being stopped when the data is updated, therefore GSAP looks for an element to animate which is being returned as null, therefore throwing the error. My advice is to try a version of the app with no animations whatsoever and just show the filtered elements (dots on the map) and then if that works add GSAP to the mix, remembering to stop, kill and re-create the animation again as the data changes. Sorry I can't help you more than this but unfortunately Stackblitz doesn't give us more to work with. Hopefully this will help you in some way. Happy Tweening!!!
  4. Hey, basically when you want to stop the timeline and create it again you don't need to pass the duration or anything to the pause method, because that would create a jump to the timeline's end and that could look a bit odd (unless that is exactly what you're after). Since I presume that the progress of the timeline is not needed as a state property in the component, you can create an instance property in the constructor to store and update the progress: constructor() { super(); // default to 0 or null this.currentProgress = 0; } Then when you pause the timeline you can run this code // stop the timeline this.tl.pause(); // record it's progress this.currentProgress = this.tl.progress(); // kill the timeline this.tl.kill().invalidate(); // then create the timeline again this.animateMapMarkers(); // set the updated timeline's progress to the one stored and resume this.tl.progress(this.currentProgress).play(); That is the most logical and simple sequence I can think of to do that. As for the click events, I took a quick look at the API of react map gl yesterday and by going through it quite fast is not extremely simple to get up-to-speed with it. Perhaps a more in-depth dive and playing with it would allow getting your feet wet and better understand how it works. Happy Tweening!!!
  5. Hey Stephen, First thanks for supporting GSAP by buying a license, very cool of you guys!! Second, I had a chance to take a peek at the code (not an in-depth look though) and what caught my attention is this: componentDidUpdate(){ console.log("========\n Updated \n========\n") this.animateMapMarkers() console.log("2 Progress on update: ", this.tl.progress()) } This code is executed on every update, at some point your component could have more properties in the state object or props coming from the parent component or a store (Redux, Mobx, etc), so you need to update the animation only on a specific state update, one that actually calls for completely creating the animation again. My guess is that the slider progress shouldn't trigger a side effect that re-creates the animation but updates it's progress. Keep in mind that the componentDidUpdate method has a couple of params pass to it that allows you to compare the previous state and props with the new ones and execute code accordingly https://reactjs.org/docs/react-component.html#componentdidupdate Perhaps that is the reason why the slider is not working, because every time the slider is updated the state property is updated as well and that trigger the componentDidUpdate method creating the animation again with it progress at 0. As far as the map pan/zoom events if possible try to use an event start to pause the timeline and an event end to create the timeline again. For example as soon as the user starts panning the map, you pause the timeline and update the state and re-create the timeline only when the panning event is completed, like that you avoid a bunch on unnecessary renders of the component. Also If I was you on the start event I would register the current progress of the timeline, pause, kill and invalidate it and in the end event I would clear the props of all the elements, create the timeline again and set it's progress to the value you stored before. It seems that react map gl allows to create some custom events, but at a quick glance the API seems a bit convoluted to me and there are no clear examples of how to create and implement that in a component and how to subscribe to the specific events since the event handlers will reside in the same component, perhaps using a method inside the component class that instantiates a new controller adds the event listeners and returns the controller, could work. You can always ask in stack overflow and create an issue in the repo. This is as much as I can do right now, sorry for not being more helpful. Hopefully is enough to get you started. Happy Tweening!!!
  6. Hi, As mentioned before I haven't had time to dig deeply into the Hooks API and all I can offer right now is a simple example but no real explanation on how it actually works, sorry about that. Here is a live sample using a Timeline instance with React hooks: https://stackblitz.com/edit/gsap-react-hooks-timeline-instance-toggle As you can see it uses a useEffect at first run in order to create the timeline and then you can add all the child instances you want to the timeline. Unfortunately this doesn't works: let tweenTarget = null; const tl = new TimelineLite({paused: true}); useEffect(() => { tl .to(tweenTarget, 0.5, {x: 100}) .to(tweenTarget, 0.5, {y: 100}) .to(tweenTarget, 1, {rotation: 360}) .reverse(); }, []); useEffect(() => { tl.reversed(!toggle); }, [toggle]); Even though in the useEffect callback triggered by the toggle update, tl is defined and it's reversed state is updated, nothing happens. This is the part I can't give you a proper explanation about. For the foreseeable future just work with the timeline in the initial useState and then in the useEffect add the instances, like in the live sample. As soon as I have an official explanation about this, I'll post it here and in the other threads dealing with hooks. Happy Tweening!!!
  7. @SENPAI & @xraymutation, This is trickier than one can expect because instead of using RTG to animate the transition between route components, the idea is to animate in a full page overlay, change the rendered component based on the new route and then animate the overlay out. Normally in RTG you pass the component that matches the target route which is animated. One solution I can think of is to play with the entering and exiting API's from RTG in order to animate just the overlay and produce the route change using a set instance in the addEndListener in order to have everything working with GSAP's timing. Of course this is easier said than done. Hopefully during the weekend I'll have some time to check this, but I can't make any promises since I'm extremely tight right now time-wise. An alternative is to create an animation in the overlay and use react router's API to make the route changes using GSAP callbacks. The trade-off in this approach is that you loose the capacity of animating the route changes using the browser's forward and back buttons, in those cases the routes change without any animation. Let me know which approach you prefer and perhaps we can work out something together. Happy Tweening!!!
  8. On top of Zach's great advice, try to avoid using regular selectors and use $refs instead: https://vuejs.org/v2/api/#ref
  9. @danboyle8637 I made a scroll spy for a React app a while ago based on this repo: https://github.com/makotot/react-scrollspy. It is quite experimental and rudimentary, If you want I can look around to find it and give it to you so you can check it. The principle is quite simple, the code listens to the scroll event (I know is not the best way) of a main wrapper and compares the scroll top value with the position of the elements that you want to animate or in the use case of that particular project set the active menu item. When the scroll position exceeds the top position of an element and if the current element is different from the value stored in the state, it updates a visible property in the state. Like that the state is updated only once per element and not on every scroll update. Is not the most efficient way but is far more efficient than constantly updating the state on every scroll event.
  10. Honestly I'm out of my element with the intersection observer API here so I won't be able to help you with that, sorry The one thing that gets my attention is the fact that the animation's target is the same element. If we're not talking about a dynamic element why not create the animation in the same component and trigger it with the intersection observer (if that is even possible). By playing a bit with your code and adding some callbacks I can see that the animation is actually starting, updating and completing, so the issue lays on the DOM node passed to it not being affected by the GSAP instance which is odd. Unfortunately the only advice I can give you is try to create your animation inside the component and just control that instance instead of creating it over and over again and use that in the component's hook.
  11. Honestly I haven't played with the intersection observer API at all. By doing some quick reading on the subject I don't see any issue as long as you're careful about passing an actual DOM node to the function that creates the GSAP instance. IMHO I don't see any big issue on keeping the code that creates the GSAP instances inside the components unless is exactly the same code for a bunch of different components, and I mean that in the DRY-way (Don't Repeat Yourself), ie, if you don't want to write the same code over and over again. Regarding the kill feature, this is not like a biological kill in terms that the GSAP instance ceases to exist, basically the instance is stopped and you can be sure that is not moving in any direction and that anything related to it will be executed until is explicitly set in that way. If you want to completely remove the instance you can reset it's reference in memory with null. The only check I can think of is the isActive() method, that should return false if the GSAP instance was killed. Finally the GSAP instance should be killed even though is instantiated in a different file because the DOM node will have a reference to the instance's position in memory, this does not depends of the context where the animation is actually created, which is exclusive of the code block where it happens. Also keep in mind that this will eventually happen in the same file but in a specific closure of the bundled file between lines X and Y. Happy Tweening!!
  12. Ha!!! is already complicated enough, so no thanks!!!
  13. I could tell you, but after I'd have to kill you... Absolutely is a matter of having the time to create the samples and update the guide as well. Is definitely in my to-do list:
  14. Hi and welcome to the GreenSock forums. Sorry to hear that you're experiencing problems with GSAP. Unfortunately it seems to be an issue with some CORS issue accessing bundlephobia.com's API, so the live sample is not working, for me at least. In this post is discussed how to create and toggle animations using the Hooks API: Also you can check a live simple example here as well: https://stackblitz.com/edit/gsap-react-hooks-toggle For I can see in your code you're using two different timelines to affect the same elements into different values. Ideally try to create a GSAP instance that you can toggle for each sub-menu element. Also you're adding new instances to the timeline every time the component is updated, so try to add an empty array when creating the GSAP instances so that code runs only when the component is mounted and toggle the animations using another useEffect call only when the open state property is updated. Hopefully this can help you as you try to get a working live sample so we can take a better look at it. Happy tweening!!
  15. Hi, you can create the split text as a property in the component's class, in the constructor: constructor (props) { super(props); this.title = null; this.titleChars = null; } Here this.title should point to a ref in the render method Then in the component did mount method you can create the SplitText instance and assign the chars to the property created in the constructor: componentDidMount () { const mySplit = new SplitText(this.title, { type: "words, chars", position: "absolute" }); this.titleChars = mySplit.chars; // array of DOM elements (<div> tags) TweenMax.staggerTo(this.titleChars, 1, {x: 10, y:-10, rotation: 180, autoAlpha: 0}, 0.1); } That is working for me, give it a try and let us know how it works. Happy tweening!!