带有react和redux的TransitionGroup:用动画替换旧元素

时间:2017-01-04 13:39:12

标签: javascript reactjs redux react-redux reactcsstransitiongroup

考虑一个用例:一个内部有文本的块(文本从商店中获取)。当文本改变时 - 块平滑消失,另一个块出现。

伪代码以便更好地说明:

import TransitionGroup from 'react-addons-transition-group'

@connect((state) => ({text: state.text}))
class Container extends React.Component {
  render() {
    return (
      <div>
        <TransitionGroup>
          <Block key={this.props.text}/> // change block when text changes
        </TransitionGroup>
      </div>
    )
  }
}

@TransitionWrapper() // pass componentWillEnter through wrapper
@connect((state) => ({text: state.text}), null, null, {withRef: true})
class Block extends React.Component {
componentWillEnter(callback) {
    // fancy animations!!!
    const el = ReactDOM.findDOMNode(this); 
    TweenMax.fromTo(el, 1, { 
      alpha: 0, 
    }, { 
      alpha: 1, 
      onComplete: callback 
    }); 
  }

  componentWillLeave (callback) { 
    const el = ReactDOM.findDOMNode(this); 
    TweenMax.to(el, 1, { 
      alpha: 0, 
      onComplete: callback 
    }); 
  }

  render() {
     return (
       <div>{this.props.text}</div>
     )
   }
}

state.text更改后会发生什么?

  1. 出现新的Block,因为key已更改; componentWillEnter为它启动动画。大。
  2. 旧块获取重新呈现componentWillLeave为其启动动画。
  3. 当第一个动画完成重新渲染时再次发生。
  4. 问题是第2步:旧元素应该与旧数据一起消失,但由于重新渲染它会将其内容从store更改为新内容,因此用户会看到:

    1. store.text = 'Foo'。用户看到一个带有文字的块&#39; Foo&#39;在屏幕上。
    2. store.text = 'Bar'。用户看到两个块,都带有文本&#39; Bar&#39;屏幕上。一个街区正在消失。
    3. 动画完成后,用户会在屏幕上看到一个带有文字Foo的屏幕。
    4. 我认为现在使用过渡是很常见的,这应该是一个常见的问题,但我很惊讶我找不到任何相关的东西。 我能想到的最好的想法是&#34;冻结&#34;当元素即将离开(或传递之前的store时,它就会在元素上出现道具,因此它会使用以前的数据重新渲染),但这对我来说感觉很糟糕。

      解决此问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

我们遇到了与redux存储相同的问题,因为当删除数据时,props不包含任何东西,因此,在卸载动画时,UI将不会显示任何数据。

我认为使用旧商店或州是违法的(打破React生命周期的惯例),如果没有可用的数据,你可以使用loading placeholder,例如

if (!this.props.text){
   return <EmptyPlaceholder />
}

动画持续时间也很小,如300毫秒,用户体验也不会差。

或者,您需要定义一个类实例变量,如:

componentWillMount(){
       if(this.props.text){
         this.text = this.prop.text;  
       }
    }

然后渲染文字,如

<Block key={this.props.text || this.text}/>

然后在卸载动画时,旧文本将始终存在。我测试了我的项目,它运行得很好。希望它会对你有所帮助,如果没有,请随时给我发消息。