2017-05-29 14 views
0

TransitionGroupTweenMaxを使用してカスタムModalコンポーネントをアニメーション化しようとしています。JS - TransitionGroupと高次のコンポーネントに反応する

<Container> 
    <Content> 
    // modal contents in here... 
    </Content> 
    <Overlay/> 
</Container> 

私は<Container>がフェードインしたいと<Content>は下からフェードインする:モーダルの構造を理解するには、以下の仮定的、疑似構造を検討してください。理解を深めるためのビジュアルがあります。赤は、オーバーレイを表し、白は、内側の内容を表しています。 enter image description here

私は実際に次のコードを使用して動作するように上記のビジュアルを得た:私は上記のコードのメンテナンス性の向上のために必要

import React, { Component } from 'react'; 
import TransitionGroup from 'react-transition-group/TransitionGroup'; // npm install react-transition-group --save 
import { TweenMax } from 'gsap'; // npm install gsap --save 

class ParentChild extends React.Component { 

    componentWillEnter(callback) { 
     TweenMax.fromTo(this.parent, 0.33, {opacity: 0}, {opacity: 1, onComplete: callback}); 
     TweenMax.fromTo(this.child, 0.33, {opacity: 0, y: 100}, {opacity: 1, y: 0, onComplete: callback}); 
    } 

    componentWillLeave(callback) { 
     TweenMax.fromTo(this.parent, 0.33, {opacity: 1}, {opacity: 0, onComplete: callback}); 
     TweenMax.fromTo(this.child, 0.33, {opacity: 1, y: 0}, {opacity: 0, y: 100, onComplete: callback}); 
    } 

    render() { 
     const { size, children } = this.props; 
     const parentStyle = { 
      width: `${size}px`, 
      height: `${size}px`, 
      background: '#df4747', 
      display: 'flex', 
      alignItems: 'center', 
      justifyContent: 'center' 
     }; 
     const childStyle = { 
      background: '#fff', 
      textAlign: 'center', 
      color: '#000', 
      width: '90%' 
     } 
     return(
      <div ref={el => this.parent = el} style={parentStyle}> 
       <div ref={el => this.child = el} style={childStyle}> 
        {this.props.children} 
       </div> 
      </div> 
     ); 
    } 
} 

class App extends Component { 
    constructor() { 
     super(); 
     this.state = { 
      isVisible: false 
     }; 
     this.handleToggle = this.handleToggle.bind(this); 
     this.handleClose = this.handleClose.bind(this); 
    } 

    handleToggle() { 
     this.setState({ isVisible: !this.state.isVisible }); 
    } 

    handleClose() { 
     this.setState({ isVisible: false }); 
    } 

    render() { 
     const { isVisible } = this.state; 
     return(
      <div> 
       <TransitionGroup> 
        {isVisible ? 
         <ParentChild size="150"> 
          <p>I wanna fade up!</p> 
         </ParentChild> 
        : null} 
       </TransitionGroup> 

       <button onClick={this.handleToggle}>Toggle Visibility</button> 
      </div> 
     ); 
    } 
} 

export default App; 

を高次コンポーネントの助けを借りて、私は次のように試みました。私の意見では、TweenMaxは個々のコンポーネント(fadeInHOCとfadeInUpHOC)に分離されているため、次のコードはメンテナンスが容易です。したがって、どのタイプのReactコンポーネントでも再利用できます。また、アニメーションを変更したい場合は、別のHOCを作成してラッパー機能を変更するだけです。

import React, { Component } from 'react'; 
import TransitionGroup from 'react-transition-group/TransitionGroup'; // npm install react-transition-group --save 
import { TweenMax } from 'gsap'; // npm install gsap --save 

const fadeInHOC = (Component) => { 
    return class extends React.Component { 

     componentWillEnter(callback) { 
      TweenMax.fromTo(this.container, 0.33, {opacity: 0}, {opacity: 1, onComplete: callback}); 
     } 

     componentWillLeave(callback) { 
      TweenMax.fromTo(this.container, 0.33, {opacity: 1}, {opacity: 0, onComplete: callback}); 
     } 

     render() { 
      return <Component containerRef={el => this.container = el} {...this.props}/>; 
     } 
    } 
} 

const fadeInUpHOC = (Component) => { 
    return class extends React.Component { 

     componentWillEnter(callback) { 
      TweenMax.fromTo(this.container, 0.33, {opacity: 0, y: 100}, {opacity: 1, y: 0, onComplete: callback}); 
     } 

     componentWillLeave(callback) { 
      TweenMax.fromTo(this.container, 0.33, {opacity: 1, y: 0}, {opacity: 0, y: 100, onComplete: callback}); 
     } 

     render() { 
      return <Component containerRef={el => this.container = el} {...this.props}/>; 
     } 
    } 
} 

const Parent = fadeInHOC((props) => { 
    const size = props.size; 
    const style = { 
     width: `${size}px`, 
     height: `${size}px`, 
     background: '#df4747', 
     display: 'flex', 
     alignItems: 'center', 
     justifyContent: 'center' 
    } 
    return(
     <div ref={props.containerRef} style={style}> 
      {props.children} 
     </div> 
    ); 
}); 

const Child = fadeInUpHOC((props) => { 
    const style = { 
     background: '#fff', 
     textAlign: 'center', 
     color: '#000', 
     width: '90%' 
    } 
    return(
     <div ref={props.containerRef} style={style}> 
      {props.children} 
     </div> 
    ); 
}); 

class App extends Component { 
    constructor() { 
     super(); 
     this.state = { 
      isVisible: false 
     }; 
     this.handleToggle = this.handleToggle.bind(this); 
     this.handleClose = this.handleClose.bind(this); 
    } 

    handleToggle() { 
     this.setState({ isVisible: !this.state.isVisible }); 
    } 

    handleClose() { 
     this.setState({ isVisible: false }); 
    } 

    render() { 
     const { isVisible } = this.state; 
     return(
      <div> 
       <TransitionGroup> 
        {isVisible ? 
         <Parent size="150"> 
          <Child> 
           <p>I wanna fade up!</p> 
          </Child> 
         </Parent> 
        : null} 
       </TransitionGroup> 

       <button onClick={this.handleToggle}>Toggle Visibility</button> 
      </div> 
     ); 
    } 
} 

export default App; 

上記コードの問題は<Child>fadeInUpは、<Parent>作品にのみ、外側のアニメーションをトリガしないことです。あなたが意図したとおりに動作させる方法を教えてください。私は別のアプローチを使うべきですか?高次コンポーネントを使用せずにParentChildのアプローチに固執する必要がありますか?あなたのご意見を本当にありがたいです。ありがとうございました!

答えて

0

さらにParentChildをHOCコンポーネントにラップすると、遷移グループは機能しません。TransitionGroupに反応接続されたコンポーネントをフックして同じ問題が発生した場合、ライフサイクルメソッドはまったくトリガーされません。

const WrappedChild = (props) =>{ 
    return <TransitionGroup> 
    <Child {...props}/> 
    </TransitionGroup> 
} 

、その後WrappedChildをエクスポートしてParentの子としてそれを作る、すべてのライフサイクル・メソッドがで、利用できるようになります。それを行うには

一つの方法は、のようなTransitionGroup で最初のウルChildコンポーネントをラップしていますur Childコンポーネント。これはうまく動作します。

Parentに複数の子供が含まれていると、たとえばdata.map((item)=> <Child ... />)でレンダリングし、Child自体が接続されたレフィックスコンポーネント(私たちの状況)である場合は動作しません。

もう1つの方法は、私たちの問題の解決策であるtransitionGroupの代わりにreact-movehttps://github.com/react-tools/react-move)を使用することです。それは非常に便利ですし、期間をカスタマイズし、曲線を緩和し、単一のトランジションで異なるスタイルの異なるアニメーションを定義することができます。

アニメーションを処理するのにTweenMaxは必要ありません。うまくいけばそれはあなたを助けるでしょう。

関連する問題