2015-10-29 44 views
11

次のコンポーネントをDOMに追加してフェードインする前に、最初のコンポーネントがフェードアウトしてDOMから削除される2つのコンポーネントの間でアニメートしたいと思う。 DOMは古いコンポーネントが削除される前に領域を占有します。コンポーネント間でアニメーションの反応を反応させよう

http://jsfiddle.net/phepyezx/4

// css snippet 
.switch-enter { 
    opacity: 0.01; 
} 
.switch-enter.switch-enter-active { 
    opacity: 1.0; 
} 
.switch-leave { 
    opacity: 1.0; 
} 
.switch-leave.switch-leave-active { 
    opacity: 0; 
} 

// React snippet 
<ReactCSSTransitionGroup transitionName="switch"> 
    <div key={key} className={className}>{this.text()}</div> 
</ReactCSSTransitionGroup> 

(私にとっては)受け入れられないソリューションここに見られるような新しいコンポーネントへの移行前に、CSSを使用した元のコンポーネントを非表示にすることです:

あなたはこのフィドルに問題が見ることができますhttp://jsfiddle.net/phepyezx/5

// Change to css 
.switch-leave { 
    visibility: hidden; 
    height: 0px; 
    width: 0px; 
    opacity: 1.0; 
} 

「遅延」は、元が削除される前に、新しい部品を実装から反応する方法はありますか?私はこれを達成するために速度やその他のライブラリに触れています。別の解決策は、両方とも絶対位置にそれらを持つことにより、例えば、着信と発信の要素が同じスペースを取るようにすることです

おかげ

答えて

8

componentWillUnmount()ライフサイクルメソッドを使用して解決しました。

http://jsfiddle.net/phepyezx/9/

ここでは、コードです:

var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; 

const Off = React.createClass({ 
    componentWillUnmount() { 
     this.props.handleTransitionEnd(); 
    }, 
    render() { 
     return (
      <div className="off button">OFF</div> 
     ) 
    } 
}); 

const On = React.createClass({ 
    componentWillUnmount() { 
     this.props.handleTransitionEnd(); 
    }, 
    render() { 
     return (
      <div className="on button">ON</div> 
     ) 
    } 
}); 

var Switch = React.createClass({ 
    getInitialState: function() { 
     return { 
      on: false, 
      transitionEnd: true 
     }; 
    }, 

    toggle: function(e) { 
     this.setState({ 
      on: !this.state.on, 
      transitionEnd: false 
     }); 
    }, 

    handleTransitionEnd() { 
     this.setState({transitionEnd: true}); 
    }, 

    renderOff() { 
     if (! this.state.on && this.state.transitionEnd) { 
      return (
       <Off key="off" handleTransitionEnd={this.handleTransitionEnd} /> 
      ) 
     } 
    }, 

    renderOn() { 
     if (this.state.on && this.state.transitionEnd) { 
      return (
       <On key="on" handleTransitionEnd={this.handleTransitionEnd} /> 
      ) 
     } 
    }, 

    render: function() { 
     return (
      <div> 
       <button onClick={this.toggle}>Toggle</button> 
       <ReactCSSTransitionGroup transitionName="switch"> 
       {this.renderOff()} 
       {this.renderOn()} 
       </ReactCSSTransitionGroup> 
      </div> 
     );   
    } 
}); 

React.render(<Switch/>, document.getElementById("switch")); 

し、関連するCSS:

.switch-enter { 
    opacity: 0.01; 
} 
.switch-enter.switch-enter-active { 
    opacity: 1.0; 
    transition: opacity 500ms ease-in; 
} 
.switch-leave { 
    opacity: 1.0; 
} 
.switch-leave.switch-leave-active { 
    opacity: 0; 
    transition: opacity 500ms ease-out; 
} 

あなたは絶対位置と遅延の代わりに使用するJonny Buchanan's answerと同じ効果的な結果を得ることができますcomponentWillUnmount()

+0

@JonnyBuchananあなたのアプローチの両方が役に立つようです。今ではある程度の時間が経過していますが、どのアプローチがあなたのために最適な作品を見つけましたか? @RickJolly、特定のシナリオではあなたのアプローチが最も効果的ですか?それはReactCSSTransitionGroup内の大きなリスト(子)にうまくスケールアップできますか?私が理解していることは、あなたのアプローチが余分な 'render()'サイクル(おそらく、削除される各アイテムの余分なサイクルか?利点や欠点があることが分かりましたか? (おそらくデバッグ - 余分な 'render()'で何が起こっているのか明確になるでしょうか?) –

+0

また、アニメーション化するコンポーネントが 'componentWillUnmount'を実装し、' handleTransitionEndあなたはそれが他の状況の痛みであることを発見しましたか? –

13

<ReactCSSTransitionGroup 
    className="container" 
    component="div" 
    transitionName="switch"> 
... 

.container { 
    position: relative; 
} 
.container > div { 
    position: absolute; 
} 

http://jsfiddle.net/phepyezx/7/


ますtransition-delayを使用して、入力コンポーネントが表示される前に終了コンポーネントが消えるまで待つことができます。例:

.fade-enter { 
    opacity: 0.01; 
} 
.fade-enter.fade-enter-active { 
    opacity: 1; 
    transition: opacity 1s; 
    transition-delay: 1s; 
} 

.fade-leave { 
    opacity: 1; 
} 
.fade-leave.fade-leave-active { 
    opacity: 0.01; 
    transition: opacity 1s; 
} 
+0

はいあなたは次のコンポーネントのレンダリングを遅らせたい場合、あなたはこのようなものを使用することができます。しかし、最初は完全にフェードアウトするのと全く同じ効果はありません。私は後に何が起こっているのかは間違いなく可能ではないと思います。私は、下位レベルのReactTransisionGroupのcomponentDidLeave()ライフサイクルメソッドを使用して、新しいコンポーネントをいつレンダリングするかを知るための状態を設定できると思います。もう1つのアプローチは、プレーンなjavascriptを使用して、このポストに示すように、基底のDOMノードにトランジェントエンドイベントリスナーを適用することです。http://www.chloechen.io/react-animation-done-in-two-ways/ –

+0

新しいビットについて '遷移遅延' –

+0

ありがとう!ほぼ完璧ですが、絶対的な位置付けが必要です。残念ながら、着信コンポーネントがマウントされていない場所(または表示: 'なし')には、発信コンポーネントが離れるまで何も見つかりませんでした。 –

2
import React, { Component } from 'react'; 

export default class DelayedRender extends Component { 

    static propTypes = { 
     delay: React.PropTypes.number.isRequired, 
     children: React.PropTypes.element, 
     className: React.PropTypes.string 
    }; 

    constructor(props) { 
     super(props); 

     this.state = { 
      render: false 
     }; 
    } 

    componentDidMount() { 
     setTimeout(() => { 
      const delayedClassNames = this.refs.noDelayed.className; 
      this.setState({ 
       render: true, 
       classNames: delayedClassNames 
      }); 
     }, this.props.delay); 
    } 

    render() { 
     const { children, className } = this.props; 
     return this.state.render ? 
      <div className={this.state.classNames}>{children}</div> : 
      <div className={className} ref="noDelayed" ></div>; 
    } 
} 

そして、あなたのrenderメソッドで:

const ROUTE_TRANSITION_TIME = 500; 
const views = []; 

if (shouldRenderDelayedRoute) { 
    views.push(
     <DelayedRender delay={ROUTE_TRANSITION_TIME} key="book"> 
      <A ref="book"/> 
     </DelayedRender> 
    ); 
} else { 
    views.push(<B key="library"/>); 
} 

<ReactCSSTransitionGroup 
    transitionEnterTimeout={ROUTE_TRANSITION_TIME} 
    transitionLeaveTimeout={ROUTE_TRANSITION_TIME} 
    transitionName="fade-transition" 
         > 
    {views} 
</ReactCSSTransitionGroup> 
関連する問題