How to implement transition animation between components in React

1. What is it

In daily development, the transition animation when switching pages is a relatively basic scene.

When a component has a transition animation during the display and disappearance process, it can greatly increase the user experience.

There are many options for implementing transition animation effects in react, such as react-transition-group, react-motion, Animated, and native CSS can complete switching animations

Second, how to implement

In react, react-transition-group is a good solution, which adds enter to elements, enter- active, exit, exit-active this series of hooks

It can help us conveniently implement the entry and exit animation of components.

It mainly provides three main components:

  • CSSTransition: In front-end development, combine CSS to complete the transition animation effect
  • SwitchTransition: This component is used when two components show and hide switching.
  • TransitionGroup: wraps multiple animation components in it, generally used for animation of elements in the list

CSSTransition

The principle of animation is that when the in attribute of CSSTransition is set to true, CSSTransition will first give it Add xxx-enter and xxx-enter-active‘s class to the subcomponent to perform animation.

When the animation ends, the two classs will be removed and the class of -enter-done will be added.

So you can take advantage of this and use the transition attribute of css to make the element smoothly transition between the two states, thereby obtaining the corresponding animation effect.

When the in attribute is set to false, CSSTransition will add xxx-exit and to the child component. class of xxx-exit-active, and then start executing the animation. When the animation ends, remove the two class, and then add -enter- class of done

Examples below:

export default class App2 extends React.PureComponent {

  state = {show: true};

  onToggle = () => this.setState({show: !this.state.show});

  render() {
    const {show} = this.state;
    return (
      <div className={'container'}>
        <div className={'square-wrapper'}>
          <CSSTransition
            in={show}
            timeout={500}
            classNames={'fade'}
            unmountOnExit={true}
          >
            <div className={'square'} />
          </CSSTransition>
        </div>
        <Button onClick={this.onToggle}>toggle</Button>
      </div>
    );
  }
}

The corresponding css style is as follows:

.fade-enter {
  opacity: 0;
  transform: translateX(100%);
}

.fade-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: all 500ms;
}

.fade-exit {
  opacity: 1;
  transform: translateX(0);
}

.fade-exit-active {
  opacity: 0;
  transform: translateX(-100%);
  transition: all 500ms;
}

SwitchTransition

SwitchTransition can complete cool animations switching between two components

For example, there is a button that needs to switch between on and off. We hope to see on exit from the left first, and offEnter from the right

There is mainly one attribute mode in SwitchTransition, which corresponds to two values:

  • in-out: Indicates that new components enter first and old components are removed;
  • out-in: means that the component is removed first, and then the new component is added.

The SwitchTransition component must have CSSTransition and cannot directly wrap the component you want to switch.

The CSSTransition component inside no longer accepts the in attribute to determine the state of the element as before. Instead, it uses the key attribute.

An example of button entry and exit is given below, as follows:

import { SwitchTransition, CSSTransition } from "react-transition-group";

export default class SwitchAnimation extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      isOn: true
    }
  }

  render() {
    const {isOn} = this.state;

    return (
      <SwitchTransition mode="out-in">
        <CSSTransition classNames="btn"
                       timeout={500}
                       key={isOn ? "on" : "off"}>
          {
          <button onClick={this.btnClick.bind(this)}>
            {isOn ? "on": "off"}
          </button>
        }
        </CSSTransition>
      </SwitchTransition>
    )
  }

  btnClick() {
    this.setState({isOn: !this.state.isOn})
  }
}

The css file corresponds to the following:

.btn-enter {
  transform: translate(100%, 0);
  opacity: 0;
}

.btn-enter-active {
  transform: translate(0, 0);
  opacity: 1;
  transition: all 500ms;
}

.btn-exit {
  transform: translate(0, 0);
  opacity: 1;
}

.btn-exit-active {
  transform: translate(-100%, 0);
  opacity: 0;
  transition: all 500ms;
}

TransitionGroup

When there is a group of animations, these CSSTransition can be put into a TransitionGroup to complete the animation

Similarly, there is no in attribute in CSSTransition, and the key attribute is used.

When TransitionGroup senses that children has changed, it first saves the removed nodes and then actually removes them when the animation ends.

The way it is handled is as follows:

  • For the inserted node, render the DOM first and then animate it.

  • For deleted nodes, animate them first and then delete the dom.

as follows:

import React, { PureComponent } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group';

export default class GroupAnimation extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      friends: []
    }
  }

  render() {
    return (
      <div>
        <TransitionGroup>
          {
            this.state.friends.map((item, index) => {
              return (
                <CSSTransition classNames="friend" timeout={300} key={index}>
                  <div>{item}</div>
                </CSSTransition>
              )
            })
          }
        </TransitionGroup>
        <button onClick={e => this.addFriend()}> + friend</button>
      </div>
    )
  }

  addFriend() {
    this.setState({
      friends: [...this.state.friends, "coderwhy"]
    })
  }
}

The corresponding css is as follows:

.friend-enter {
    transform: translate(100%, 0);
    opacity: 0;
}

.friend-enter-active {
    transform: translate(0, 0);
    opacity: 1;
    transition: all 500ms;
}

.friend-exit {
    transform: translate(0, 0);
    opacity: 1;
}

.friend-exit-active {
    transform: translate(-100%, 0);
    opacity: 0;
    transition: all 500ms;
}