2017-05-29 72 views
0

我正在尝试使用TransitionGroupTweenMax动画自定义模态组件。要了解模态的结构,请考虑以下的假设,伪结构:React 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; 

与上面的代码的问题是fadeInUp<Child>不会被触发,只有外层的动画作品<Parent>。你能告诉我如何让它按预期工作吗?我应该使用不同的方法吗?我应该坚持使用ParentChild方法而不使用更高阶的组件吗?我真的很感激你的意见。谢谢!

回答

0

如果您在HOC组件中进一步包装了ParentChild,转换组将不起作用,我们也通过将TransitionGroup与反应连接的组件挂钩来满足相同的问题,生命周期方法根本不会被触发。

一种方式来做到这一点是包乌尔Child组件先用TransitionGroup 像:

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

,然后导出WrappedChild,并使其作为Parent一个孩子,所有的生命周期方法将可在ur Child组件。这在你的情况下可以正常工作。

但是,如果你的Parent包含多个孩子,比如说,通过data.map((item)=> <Child ... />)Child本身呈现为连终极版组件(我们的情况),这是行不通的。

另一种方法是使用react-movehttps://github.com/react-tools/react-move)而不是transitionGroup,这是我们问题的解决方案。它非常方便,您可以自定义持续时间,缓动曲线,在一次转换中定义不同风格的不同动画。

然后你不需要TweenMax来处理动画。希望它会帮助你。