Add an animation on a React component before disappearing

Let's assume that you want to add an animation before hiding a React component.

Normally, you would have:

jsx
import React, { useState } from 'react'

const Modal = () => {

    const [display, setDisplay] = useState(true)

    const hide = () => {

        setDisplay(false)

    }

    return(
        <div>
        { display
        ? <div className = 'Modal'>
            <button onClick = {hide}>Click me to hide</button>
          </div>
        : null
        }
        </div>
    )

}

export default Modal

The problem is that the hide() function occurs instantaneously, so you can't see any animation effect after clicking on the button (the modal closes suddenly).

A solution to avoid this problem is to add a class to the element for n milliseconds before hiding it.

Example:

javascript
const hide = async (ms) => {

    // Sets a temporary class
    setAnimation('close')

    // Waits for n milliseconds 
    await new Promise(r => setTimeout(r, ms))

    // Hides the element
    setDisplay(false)

}

So, the final component would be:

jsx
import React, { useState } from 'react'

const Modal = () => {

    const [animation, setAnimation] = useState('open')
    const [display, setDisplay]     = useState(true)

    const hide = async (ms) => {

        setAnimation('close')

        await new Promise(r => setTimeout(r, ms))

        setDisplay(false)

    }

    return(
        <div>
        { display
        ? <div className = {`Modal ${animation}`}>
            <button onClick = {() => hide(1000)}>Click me to hide</button>
          </div>
        : null
        }
        </div>
    )

}

export default Modal

Finally, you can create two different animations (for opening the modal and for closing it):

CSS
.Modal.open{
    animation: bounce-in 1s ease-in;
}
.Modal.close{
    animation: bounce-out 1s ease-in;
}
@keyframes bounce-in{
    0%    {opacity: 0;   transform: scale(0.5);}
    100%  {opacity: 1;   transform: scale(1);}
}
@keyframes bounce-out{
    0%    {opacity: 1;   transform: scale(1);}
    100%  {opacity: 0;   transform: scale(0.5);}
}

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.