javascriptreactjsreact-animated

How to apply animation in React JS


I'm using react-animated-css library to apply animations on state change in React JS.

The code is as follows:

import ReactDOM from "react-dom";
import React, { Component } from "react";
import { Animated } from "react-animated-css";

const animationIn = "fadeInLeft";
const animationOut = "fadeOutLeft";
const animationDuration = 400; // in ms

const arr = [
  {
    id: 1,
    name: "Test"
  },
  {
    id: 2,
    name: "Test1"
  },
  {
    id: 3,
    name: "Test3"
  },
  {
    id: 4,
    name: "Test4"
  },
  {
    id: 5,
    name: "Test5"
  }
];

class Selection extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selection: []
    };
    this.addSelection = this.addSelection.bind(this);
    this.removeItem = this.removeItem.bind(this);
  }

  addSelection(item) {
    const exists = this.state.selection.find(i => i.id === item.id);
    if (exists === undefined) {
      this.setState({ selection: [...this.state.selection, item] });
    }
  }

  removeItem(item) {
    this.setState({
      selection: this.state.selection.filter(i => i.id !== item.id)
    });
  }

  render() {
    return (
      <div
        style={{
          display: "flex",
          flexDirection: "row",
          justifyContent: "space-between"
        }}
      >
        <div>
          <h2>Choose from the list</h2>
          {arr.map(item => {
            return (
              <div
                key={item.id}
                style={{ marginBottom: 5, cursor: "pointer" }}
                onClick={() => this.addSelection(item)}
              >
                {item.name}
              </div>
            );
          })}
        </div>

        <div>
          <h1>Selection</h1>
          {this.state.selection.length < 1 ? (
            <div>Nothing selected</div>
          ) : (
            this.state.selection.map(l => {
              return (
                <Animated
                  key={l.name}
                  animationIn={animationIn}
                  animationOut={animationOut}
                  animationInDuration={animationDuration}
                  animationOutDuration={animationDuration}
                  isVisible={true}
                >
                  <div key={l.id} style={{ marginBottom: 5 }}>
                    {l.name}
                    <button
                      onClick={() => this.removeItem(l)}
                      style={{ marginLeft: 5, cursor: "pointer" }}
                    >
                      Remove
                    </button>
                  </div>
                </Animated>
              );
            })
          )}
        </div>
      </div>
    );
  }
}

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

It works fine when I click on some item on the left and add it to the state, but when I remove it it doesn't work.

Here is the example on sandbox.

Any idea how to apply the animation also on removing items from the state?


Solution

  • You need to play with the state of the props visible of your animation and add timeout.

    addSelection(item) {
        const exists = this.state.selection.find(i => i.id === item.id);
        if (exists === undefined) {
          this.setState({
            selection: [...this.state.selection, item],
            [`visibleAnimate${item.id}`]: true
          });
        }
      }
    
      removeItem(item) {
        this.setState(
          {
            [`visibleAnimate${item.id}`]: false
            // selection: this.state.selection.filter(i => i.id !== item.id)
          },
          () => {
            setTimeout(() => {
              this.setState({
                selection: this.state.selection.filter(i => i.id !== item.id)
              });
            }, 300);
          }
        );
      }
    

    Here the sandbox demo.