Jump to content

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

Rodrigo last won the day on May 2

Rodrigo had the most liked content!


  • Posts

  • Joined

  • Last visited

  • Days Won


Rodrigo last won the day on May 2

Rodrigo had the most liked content!


About Rodrigo

Profile Information

  • Gender
  • Location
    Santiago - Chile

Recent Profile Visitors

30,139 profile views
  1. The GSAP instance is being stored in a reference that will be kept through re-renders, unless you update the ref.current value by hand: Perhaps that should be re-phrase to: "store the timeline in a reference using useRef()", but I believe the point is pretty clear. Finally Blake is right, in most cases when using HMR, an update to the code might keep state but reset other stuff, which can result in the DOM elements going to their initial state, which can conflict specially with .from() instances and other GSAP instances. In those cases the good ol' F5 key is the only solution for that. Happy Tweening!!!
  2. Hi and welcome to the GreenSock forums. In order to make the plugins work in Next you need to import them from the dist folder: import { ScrollTrigger } from "gsap/dist/ScrollTrigger"; Finally if you run into some issues with the register part, be sure to check for the window object and not the process.browser property: if (typeof window !== "undefined") { gsap.registerPlugin(ScrollTrigger); } Happy Tweening!!!
  3. That happens because all of them are in the DOM at the same time, you can solve that by tinkering with the position styles in order to take one or all of them from document flow or use the switch transition component: https://reactcommunity.org/react-transition-group/switch-transition Happy Tweening!!!
  4. The done callback should be able to do that on both cases enter/exit. Keep in mind that enter and exit are different things, similar to how GSAP handles display: "none"/"block". The real thing is that done and timeout are just used to update the state of the <Transition> component, nothing more. Depending on a specific state property the component is either rendered or not. I don't want to get into more specifics because, IMHO we don't need even more confusion about the usage of GSAP in a React app around here Here you can see the render method of the <Transition> component (a class component maintained by the React team, go figure ): https://github.com/reactjs/react-transition-group/blob/master/src/Transition.js#L342-L378 At the top you find the conditional rendering logic for it: const status = this.state.status if (status === UNMOUNTED) { return null } The status property changes between this values depending on the stage of the transition: export const UNMOUNTED = 'unmounted' export const EXITED = 'exited' export const ENTERING = 'entering' export const ENTERED = 'entered' export const EXITING = 'exiting' If you follow the logic in the componentDidUpdate hook and the associated callbacks you'll see that this isn't exactly setting up a nuclear reactor, is quite simple actually. In this sample you can check it in dev tools, is a bit outdated but the mechanics of it are pretty much the same. If you add a new element is mounted then animated in. If you remove an element is animated out and then unmounted from the DOM: https://stackblitz.com/edit/gsap-react-transition-group-list?file=transition-card.js Finally I don't know all the ins and outs of transition group but is a great package and certainly quite useful in some specific cases.
  5. @granularclouds Be more careful with your syntax <Transition in={key === color} onExt={exit} // onExit <--!!!!!!! onEntering={(el) => enter(el, i)} mountOnEnter unmountOnExit appear timeout={1500} > Happy Tweening!!!
  6. Indeed you are : const exit = (node) => { gsap.from(node, { duration: 1.5, delay: 0.5, opacity: 1, stagger: 0.5 }); }; You're creating a from instance. That basically takes the elements from the values you're passing to it in the config object to the current ones the DOM element has. So basically this code is saying: "Take this cards and animate them from opacity: 1 to their current opacity". Turns out that their current opacity is also one, so GSAP is actually doing it's job, but this is animating the opacity from one to one, so visually there is no change at all. This should work: const exit = (node) => { gsap.to(node, { duration: 1.5, delay: 0.5, opacity: 0, stagger: 0.5 }); }; Happy Tweening!!!
  7. The issue is that the in property in the <Transition> component has to be a boolean that defaults to false and now you're passing a string, so yeah the new element is being animated in when is mounted, but when the radio selection changes the elements are removed immediately, so basically is just acting as a conditional rendering logic, nothing more: https://reactcommunity.org/react-transition-group/transition#Transition-prop-in @granularclouds what you should do is create a way to loop through the object, then loop through the array of each object element and return the <Transition> component for each one. This code seems to do the trick: return ( <div className="App"> <div> <div className="radio-container"> /* ... */ </div> <div className="card-container"> <TransitionGroup> <div className="cards"> {(() => { let test = []; for(let key in colors) { const elements = colors[key].map((item, i) => <Transition in={key === color} key={item.title} onExit={exit} onEntering={(el) => enter(el, i)} mountOnEnter unmountOnExit appear timeout={1500} > <div className="card"> <h1> {item.title}</h1> <h6>{item.subtitle}</h6> </div> </Transition> ); test = [...test, ...elements]; } return test; })()} </div> </TransitionGroup> </div> </div> </div> ); This could also be broken into smaller components in order to keep the code cleaner and easier to read. Also is recommended to match the timeout property in the <Transition> component to the duration of the GSAP instance, the timeout property tells transition group when to remove the elements and update the enter/exit state properties. Happy Tweening!!!
  8. Hi, In the case of Next you need to import the file from the dist folder: import { ScrollTrigger } from "gsap/dist/ScrollTrigger"; Happy Tweening!!!
  9. Hi, The main problem here is that the code in the Navigation component is running before everything is being updated after creating the smooth scroller instance, that's why this only works in a HMR because the smooth scroll instance is already created. To be completely honest I haven't used any smooth scroll packages in production so I don't have a lot of knowledge in that regard, also I really don't like them, IMHO they create more problems than they solve and I really don't like anything that creates more problems that it solves in any aspect of life, but that's just a personal opinion. The only solution I can come up with that is actually working is to add a timeout in the Navigation component: const Navigation = () => { useEffect(() => { gsap.registerPlugin(ScrollTrigger); setTimeout(() => { gsap.to(".pin-item", { opacity: 1, x: 100, scrollTrigger: { trigger: ".pin-trigger", markers: true, pin: true, pinSpacing: false } }); }, 50); }, []); return ( <div className="pin-trigger"> <h1 className="pin-item">hello</h1> </div> ); }; But this is less than ideal and every React developer will tell you the same, but honestly I can't think of any other way and I don't have a lot of time to go through this and find out. You're using Next and I believe that the idea is to create an animated nav bar that animates down when the user scrolls down in order to make it visible, right? Perhaps you could create the animation in the navigation component and create the Scroll Trigger instance in the layout component where you could instantiate the smooth scroll package as well. You can do that using forward refs, you can read more about it here: https://reactjs.org/docs/forwarding-refs.html Here is a simple example: https://codesandbox.io/s/react-hover-forward-ref-ybtgs But those are just ideas since I have no experience with these smooth scroll packages in production. Perhaps @elegantseagulls has dealt with them and could offer some advice on the subject. Happy Tweening!!!
  10. Hi, Adding a start point to your ScrollTrigger instances seems to work: gsap.fromTo( w, { x }, { x: xEnd, scrollTrigger: { trigger: section, start: "top 92%", scrub: 0.5 } } ); Also it's a good idea to pass an array of dependencies to your useEffect hook in order to prevent it from running everytime the state or a property of the component is updated: useEffect(() => { // code here }, []); The array can have dependencies or not, read more about it here: https://reactjs.org/docs/hooks-effect.html Happy Tweening!!!
  11. Hi and welcome to the GreenSock forums. The issue is that right now you're executing the function, so as soon as the browser gets to that part of the code the playSound function is executed. GSAP has an excellent callback system that allows you to pass parameters, set scope, etc. This should work as expected: tl.to("#knapp", { background: "#a6a6a6", onComplete: playSound, onCompleteParams: ["knapp0"] }); Here you can learn more about callbacks, just scroll down to the Special Properties section: https://greensock.com/docs/v3/GSAP/gsap.to() Happy Tweening!!!
  12. You could also take a look at this sample by @mikel Happy Tweening!!!
  13. HI, Cassie is completely right, you need to move your GSAP code to a useEffect or useCallback hook. Most of the time a useEffect hook should be enough, but if you run into some issues you might need to switch to a useCalback or useLayoutEffect. Right now when react runs your code, it does it in the regular JS way, so it starts at the top and goes through it until everything is ran. The issue is that your GSAP code runs before the return statement that actually tells react what it should add to the DOM. A useEffect hook with an empty dependencies array: useEffect(() => { let frame_count = 9 let offset_value = 100 const t = gsap.to(imageViewer.current, { scrollTrigger: { trigger: imageScene.current, start: "top top", end: "+=" + (frame_count * offset_value), pin: true, scrub: true } }); // Clean up before unmounting the component/page return () => { t.kill(); ScrollTrigger.getAll().forEach(e => e.kill()); }; }, []); You can learn about the useEffect hook here: https://reactjs.org/docs/hooks-effect.html https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup Finally since you're using Next, is not really a good idea to check the process object to see if the code is running on the client or the server, that is basically an object created and used by webpack, is better to check if the window is undefined or not: if (typeof window !== "undefined") { gsap.registerPlugin(ScrollTrigger); } Happy Tweening!!!
  14. Hi, This is how the position parameter works: Happy Tweening!!!
  15. Hi, Just to add on Paul and Blake great advice, here are a couple of live samples in React that toggle a GSAP instance. This one uses a regular click handler: https://codesandbox.io/s/simple-gsap-instance-toggle-xc741 This one uses a state property to toggle the instance: https://codesandbox.io/s/gsap-toggle-instance-with-hooks-t9uqr Happy Tweening!!!