React动画API之ReactTransitionGroup用法

最近做的一个 React项目,因为频繁使用动画,考虑到快速开发和更好的可维护性,决定使用其他库来辅助,期间看到 React官网 提供的两个 API,决定尝试一下。

其中高级 API使用起来没什么难度,用过 Angular 或者 Vue 动画的人基本上扫一眼文档就能上手,但是 另外一个 底层API: ReactTransitionGroup,官网上几乎没什么介绍,只将几个生命周期的钩子函数罗列了一下,网上也没有什么关于这方面的讲解或者 Demo之类的东西,基本上都是围绕高级API ReactCSSTransitionGroup的。

因为需要对动画进行细粒度的控制,所以必须要用底层API才行,网上找不到使用的例子,没办法,只好自己亲自上手一个个实验,好在最后差不多算是弄清楚是怎么用的了。


钩子函数

React官网上对底层 API ReactTransitionGroup的解释:

ReactTransitionGroup是动画的基础。它通过 require('react-addons-transition-group)访问。当子级被声`明式的从其中添加或移除(就像上面的例子)时,特殊的生命周期挂钩会在它们上面被调用。

六个特殊的生命周期钩子函数如下:

  1. componentWillAppear()
    ReactTransitionGroup是动画的基础。它通过require('react-addons-transition-group')访问。当子级被声明式的从其中添加或移除(就像上面的例子)时,特殊的生命周期挂钩会在它们上面被调用。
  2. componentDidAppear()
    在 传给 componentWillAppear 的 回调 函数被调用后调用。
  3. componentWillEnter(callback)
    对于被添加到已存在的 TransitionGroup 的组件,它和 componentDidMount() 在相同时间被调用 。它将会阻塞其它动画发生,直到callback被调用。它不会在 TransitionGroup 初始化渲染时被调用。
  4. componentDidEnter()
    在传给 componentWillEnter的回调函数被调用之后调用。
  5. componentWillLeave(callback)
    在子级从 ReactTransitionGroup 中移除时调用。虽然子级被移除了,ReactTransitionGroup 将会保持它在DOM中,直到callback被调用。
  6. componentDidLeave()
    willLeave callback 被调用的时候调用(与 componentWillUnmount同一时间)

相信应该有不少人在看了上述官网讲解后依然是一头雾水,虽然六个钩子函数每一个都说的很仔细,但到底怎么用,可能还是不清楚,至于钩子函数中存在的回调函数 callback 到底是什么东西,就更不明白了。

对于这两点我也是很疑惑,不过实验了一番后,至于弄明白是怎么回事了,先上代码:

// Example.js  运动组件
class Example extends React.Component {
  componentWillAppear() {
    console.log('componentWillAppear');
  }
  componentDidAppear() {
    console.log('componentDidAppear');
  }
  componentWillEnter(callback) {
    console.log('componentWillEnter');
    document.querySelector('.flyBall').className += ' changeTop'
    callback()
  }
  componentDidEnter() {
    console.log('componentDidEnter');
  }
  componentWillLeave(callback) {
    callback()
  }
  componentDidLeave() {
    console.log('componentDidLeave');
  }
  render() {
    return (
      <div className="flyBall">div>
    )
  }
}

其中 changeTop样式为:

.changeTop {
  animation: move 5s;
}
@keyframes move
{
from {left:0px;}
to {left:200px;}
}
// 引入运动组件
import Example from 'Example'

class Main extends React.Component {
constructor(props) {
    super(props)
    this.state = {
      show: false
    }
  }
    render() {
        return (
          <div className="box1">
            "div">
              {
                this.state.show && 
              }
            
            
          div>
        )
  }
}

效果如下:
这里写图片描述

可以看到,动画的钩子函数,其实也就算是一种特殊的生命周期。

其中, 在本例中, componentWillAppearcomponentDidAppear这两个钩子函数没有执行,这是因为这两个钩子函数与 componentWillEntercomponentDidEnter这两个钩子函数是 互斥的,什么意思呢?

componentWillAppearcomponentDidAppear这两个钩子函数,只能在ReactTransitionGroup初始化的时候,被在刚开始就存在于ReactTransitionGroup中的子元素所触发,并且只能触发一次,后来追加进来的子元素只会触发 componentWillEntercomponentDidEnter,而不会触发 Enter

在初始化挂载,所有的ReactCSSTransitionGroup 子级将会 appear 但不 enter。然而,所有后来添加到已存在的 ReactCSSTransitionGroup 的子级将 enter但不 appear

说的简单点,同一个生命周期中,触发了 componentWillEntercomponentDidEnter,那么就不会触发 componentWillAppearcomponentDidAppear,反之亦然。

关于 callback需要说明的是,这东西我开始以为是自己定义的函数,然后再钩子函数中回调调用,但是却一直不明白该怎么将自己写的函数传进去,直到后来实验了几次才明白,原来这东西是内置的参数,根本不用管,如果你把这callback打印出来,就能看到其实它是这样的:

 console.log(callback, callback.name)
 // =>   "bound"  function(){[native code]}

是一个函数名为 bound的内置函数(native code)。

这个 callback的作用就是让特殊的生命周期继续往下执行,如果你不调用的话,那么就会阻滞动画的执行。

例如,如果你显式声明了:

componentWillLeave(callback) {
   // 如果想要动画继续执行,必须调用下面代码,否则元素将被阻滞 
   callback()
 }

然后如果不在这个函数中执行 callback() 的话,那么元素就会被暂停住,这个时候,就算你的组件正常的生命周期中的 componentWillUnMount 已经执行完了,组件依旧不会被卸载掉。


用法

官网上关于如何使用此 API的说法很模糊,我稍微说一下。

"ul" className="animated-list">
  ...

官网上给了这种使用方法,如果不指定 component,则默认在页面上渲染出一个 span元素,否则渲染出一个指定的元素,什么意思呢?

例如上述代码渲染出一个 ul元素,并且指定了其类名为 animated-list,其实是说上述代码会被完全替换为

    这段代码。

    你同样可以在其中添加子元素,子元素在渲染的时候会被保留。

    <ReactTransitionGroup component="ul" className="animated-list">
      <li>a li Element<li>
    ReactTransitionGroup>

    上述会被替换为:

    <ul class="animated-list">
        <li>a li Element<li>
    ul>

    你可能感兴趣的:(React,动画)