1

I have a functional React component, like that:

const RefreshButton = () => (

        <IconButton >
            <RefreshIcon />
        </IconButton>

)

What I need is to assign dynamically class attribute to child RefreshIcon node upon clicking IconButton (onClick), run CSS-animation bound to that class and remove that class as animation goes off (onAnimationEnd).

My problem is that I have absolutely no clue as of how do I refer child Component from within onClick and onAnimationEnd callbacks.

I have come across that topic, but it's all about class-based components and I'm not really sure how to adopt proposed solution, so I'd appreciate a lot if you point me to the right direction.

  • 1
    You can consider using [React transition group](https://reactcommunity.org/react-transition-group/) – junwen-k Nov 15 '19 at 14:30

3 Answers3

3

In react most things are done through state changes. When the state (or props) of a component changes the component will be re-rendered. So in your case you'll want to set the class on the element based on some state variable and then set that variable when you want to add/remove the class from the icon. Here's what that would look like:

const RefreshButton = () => {
    const [iconClass, setIconClass] = React.useState("");

    const onButtonClick = () => {
        setIconClass("animation-class");
    }

    <IconButton onClick={onButtonClick}>
        <RefreshIcon className={iconClass}/>
    </IconButton>
}
Shimmy568
  • 503
  • 2
  • 8
  • I think, I got the point. Is it safe to assume that `onAnimationEnd` I should trigger another state update to remove *animating* class? – greekcotlet Nov 15 '19 at 14:41
3

There are lots of ways to solve this. I'd use ref's and let the class change trigger the animation.

import React, { useRef } from 'react'

const RefreshButton = () => {
  const buttonInput = useRef(null);

  const onButtonClick = () => {
    // Do animations based on class change
    buttonInput.classList.add()
  };

  return (
    <IconButton onClick={onButtonClick} >
      <RefreshIcon ref={buttonInput} />
    </IconButton>
  )
}
Jurrian
  • 850
  • 6
  • 20
  • I didn't make it yet to advanced guides section of React official doc, but Refs seem to be the perfect use case for imperative animation which is exactly what I'm after. Thanks for your answer and reference. – greekcotlet Nov 15 '19 at 14:55
0

If your component is not a dynamic component and you have control of it then you can make it work with class related prop. That might look something like that:

const RefreshIcon = (props) => {
    const className = `my-class-name ${props.className}`;
    return (
        <div className={className}>...</div>
    )
}

and then in your parent component:

const RefreshButton = () => (
    [isAnimaionOn, setIsAnimationOn] = useState(false);

    <IconButton>
        <RefreshIcon className={isAnimaionOn ? "animation-on-class" : "animation-off-class"} />
    </IconButton>
)
Wojciech Dynus
  • 911
  • 5
  • 11