简体   繁体   English

是否可以在 React 中制作“useIsAnimating”钩子?

[英]Is it possible to make a `useIsAnimating` hook in React?

So I have a feature in my React app where it would be incredibly useful to know if an element is animating/going through a keyframe.所以我在我的 React 应用程序中有一个功能,它可以非常有用地知道一个元素是否正在动画/通过关键帧。

I spent all day yesterday trying tons of iterations through something like the below and lots of other abstractions, but can't seem to get it to work.昨天我花了一整天时间通过类似下面的东西和许多其他抽象来尝试大量的迭代,但似乎无法让它工作。 Any thoughts or is this just not possible?有什么想法,或者这是不可能的吗?

function useIsAnimating(ref) {
  const [isAnimating, setIsAnimating] = React.useState(false);

  useEffect(() => {
    ref?.current.addEventListener('animationstart', setIsAnimating(true)); 
    ref?.current.addEventListener('animationend', setIsAnimating(false)); 
    
    return () => {      
    ref?.current.removeEventListener('animationstart', setIsAnimating(true)); 
    ref?.current.removeEventListener('animationend', setIsAnimating(false)); 
    };
  }, [ref, setIsAnimating]);

  return isAnimating;
}

Without going too much into the reasons why you'd want to do this, the code above has a simple problem.无需过多说明您想要这样做的原因,上面的代码有一个简单的问题。

The second argument expected by addEventListener is a function that is supposed to be called when a given event gets triggered. addEventListener期望的第二个参数是 function,它应该在触发给定事件时调用。 Your code doesn't do that but instead it does this (after expanding it into a more readable form):您的代码没有这样做,而是这样做(在将其扩展为更易读的形式之后):

const animationStartListener = setIsAnimating(true);
ref?.current.addEventListener('animationstart', animationStartListener);
const animationEndListener = setIsAnimating(false);
ref?.current.addEventListener('animationend', animationEndListener);

For your code to work correctly you'd have to wrap the call to setIsAnimating(true) in a function, and pass that function as an argument to the addEventListener :为了使您的代码正常工作,您必须setIsAnimating(true)的调用包装在 function 中,并将 function 作为参数传递给addEventListener

const animationStartListener = () => setIsAnimating(true);
ref?.current.addEventListener('animationstart', animationStartListener);
const animationEndListener = () => setIsAnimating(false);
ref?.current.addEventListener('animationend', animationEndListener);

or, using shorter syntax:或者,使用更短的语法:

ref?.current.addEventListener('animationstart', () => setIsAnimating(true));
ref?.current.addEventListener('animationend', () => setIsAnimating(false));

Another thing to remember is that when you're removing a listener, you have to pass the same reference to the function as was passed to the addEventListener .要记住的另一件事是,当您删除侦听器时,您必须将相同的引用传递给 function ,就像传递给addEventListener一样。 The correct way to do this in React using React Hooks is by the use of useCallback hook:在 React 中使用 React Hooks 的正确方法是使用useCallback钩子:

function useIsAnimating(ref) {
  const [isAnimating, setIsAnimating] = React.useState(false);
  const handleAnimationStart = useCallback(
    () => setIsAnimating(true),
    [setIsAnimating],
  );
  const handleAnimationEnd = useCallback(
    () => setIsAnimating(false),
    [setIsAnimating],
  );

  useEffect(() => {
    ref?.current.addEventListener('animationstart', handleAnimationStart); 
    ref?.current.addEventListener('animationend', handleAnimationEnd); 
    
    return () => {      
    ref?.current.removeEventListener('animationstart', handleAnimationStart); 
    ref?.current.removeEventListener('animationend', handleAnimationEnd); 
    };
  }, [ref, handleAnimationStart, handleAnimationEnd]);

  return isAnimating;
}

Hope that helps you with your problem (and I didn't make any spelling mistakes here).希望这可以帮助您解决问题(我在这里没有犯任何拼写错误)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM