GSAP Tween 在 React 中每次播放时花费更长的时间

GSAP Tween taking longer on each play in React

我正在使用 GSAP 的时间轴为元素设置动画,看起来每次都花费越来越长的时间。在下面的示例中,您可以单击该框使其动画化,然后单击使其反转。您可以在我的设置中看到我没有设置任何延迟。如果你打开控制台你会看到日志需要越来越长的时间来执行 onComplete 函数中的消息。

根据我所做的研究,我似乎以某种方式添加了 Tween,但我不知道如何解决这个问题。任何帮助将不胜感激。 CodePen here.

const { useRef, useEffect, useState } = React

// set up timeline
const animTimeline = gsap.timeline({
  paused: true,
  duration: .5,
  onComplete: function() {
    console.log('complete');
  }
})

const Box = ({ someState, onClick }) => {
  const animRef = useRef();
  
  animTimeline.to(animRef.current, {
    x: 200,
  })
  
  useEffect(() => {
    someState ? animTimeline.play() : animTimeline.reverse(); 
  }, [someState])
  
  return (
    <div 
      className="box"
      onClick={onClick}
      ref={animRef}
    >
      
    </div>
  )
}

const App = () => {
  const [someState, setSomeState] = useState(false);
  return(
    <Box 
        someState={someState}
        onClick={() => setSomeState(prevSomeState => !prevSomeState)}
    />
  );
}

ReactDOM.render(<App />,
document.getElementById("root"))

问题

我认为这里的问题是你在组件函数 body 中有 animTimeline.to() 所以这增加了一个每次 渲染 .

时动画的新补间

Timeline .to()

Adds a gsap.to() tween to the end of the timeline (or elsewhere using the position parameter)

const Box = ({ someState, onClick }) => {
  const animRef = useRef();
  
  animTimeline.to(animRef.current, { // <-- adds a new tween each render
    x: 200,
  })
  
  useEffect(() => {
    someState ? animTimeline.play() : animTimeline.reverse(); 
  }, [someState])
  
  return (
    <div 
      className="box"
      onClick={onClick}
      ref={animRef}
    >
    </div>
  )
}

解决方案

使用镶嵌效果仅添加单个补间。

const animTimeline = gsap.timeline({
  paused: true,
  duration: .5,
  onComplete: function() {
    animTimeline.pause();
    console.log('complete');
  },
  onReverseComplete: function() {
    console.log('reverse complete');
  }
})

const Box = ( { someState, onClick }) => {
  const animRef = useRef();
  
  useEffect(() => {
    animTimeline.to(animRef.current, { // <-- add only one
      x: 200,
    });
  }, []);
  
  useEffect(() => {
    someState ? animTimeline.play() : animTimeline.reverse(); 
  }, [someState])
  
  return (
    <div 
      className="box"
      onClick={onClick}
      ref={animRef}
    />
  )
};

演示