Performing animations in React declaratively

Our brain thinks of animations imperatively. For example, to show a container (div), we want to expand the container from zero size to its full dimensions. And when we hide the container, we want to collapse the container from its full dimensions to zero size. The way we describe animations is imperative. How do we translate this to declarative way of writing code in React?

In this article, we will animate the show / hide action of a div container.

 

Render function

The render function of our App component has the button and the container to animate.

render() {
    return (
        <div className="app">
            <button
                onClick={this.handleShowToggle.bind(this)}
            >
                {this.state.show ? "Hide" : "Show"}
            </button>
            <div className={`box ${this.state.className}`} />
        </div>
    );
}

We toggle the button title based on the show state. We want to animate the div with box as className. To animate, we attach different classes to the box container. These classes indicate that the animation is in progress.

Animations using classes

When we click on “Show” button, we set the class to “box-expanding”. After the show animation is complete, we set the class to “box-expanded”

Similarly, when we click on “Hide” button, we set the class to “box-collapsing”. After the hide animation is complete, we set the class to “box-collapsed”.

The handleShowToggle function performs the className changes.

handleShowToggle() {
    let { show } = this.state;
    show = !show;
    const className = show ? 'box-expanding' : 'box-collapsing';
    this.setState({ show, className });
    setTimeout(() => {
        const className = show ? 'box-expanded' : 'box-collapsed';
        this.setState({ className });
    }, 3000);
}

CSS Transitions

The animation duration is 3 seconds or 3000 milliseconds. As we expect, box-expanding and box-collapsing classes have CSS transitions.

.box-expanding {
    width: 300px;
    height: 100px;
    transition: width 3s, height 3s;
}

.box-expanded {
    width: 300px;
    height: 100px;
}

.box-collapsing {
    width: 0;
    height: 0;
    transition: width 3s, height 3s;
}

.box-collapsed {
    width: 0;
    height: 0;
}

For the sake of completeness, we add a few more styles to our app.

.app {
    display: flex;
    flex-direction: column;
    padding: 20px;
}

.app button {
    padding: 10px;
    font-size: 16px;
    width: 100px;
    background-color: darkred;
    color: white;
}

.box {
    background-color: gold;
    margin-top: 20px;
}

To do it the React way, we have to define a class for the duration of the animation. And that class has CSS transitions set in it. In our case, the expanding and collapsing classes have transitions which affect the width and height of the container.

Related Posts

Leave a Reply

Your email address will not be published.