cheapsteak / react-transition-group-plus

A more full-featured transition group for React
Other
268 stars 20 forks source link

Example of slide up or slide down with react-transition-group-plus #24

Closed dagda1 closed 7 years ago

dagda1 commented 7 years ago

I'm struggling to find an example with react-transition-plus, do I need to use something like gsap-promise?

I want a generic animation component that wraps children:

export class TransitionComponent extends Component {
  render() {
    return (
      <Container>
        <TransitionGroup component="div">
          {children}
        </TransitionGroup>
      </Container>
    );
  }
}

Then I want to wrap components in the component:

 {expand &&
<div>
   <TransitionComponent transitionName="slide">
      {children}
    </TransitionComponent>
</div>}

In the above scenario, the element will not be in the dom until the expand condition is true.

Can anyone give me any pointers how I can achieve this with react-transition-group-plus?

cheapsteak commented 7 years ago

Hi dagda

Think of TransitionGroup as the "orchestrator" for components that come and go. The components nested inside the orchestrator can be conditionally added and removed, but the orchestrator itself cant

The following work should work, assuming that the components in children have the required animation lifecycle hooks (componentWillEnter, componentWillAppear, componentWillLeave)

<div>
   <TransitionComponent transitionName="slide">
      {expand && children}
    </TransitionComponent>
</div>
dagda1 commented 7 years ago

Thank you for the reply, so far I have this:

import React, { Component } from 'react';
import TransitionGroup from 'react-transition-group-plus';

type Props = {
  children: React$Element<*>,
  show: boolean
};

export class TransitionComponent extends Component {
  props: Props;
  componentWillAppear(callback) {
    console.log('enter');
    const el = this.container;
    TweenMax.fromTo(
      el,
      0.3,
      { y: 100, opacity: 0 },
      { y: 0, opacity: 1, onComplete: callback }
    );
  }

  componentWillLeave(callback) {
    console.log('leave');
    const el = this.container;
    TweenMax.fromTo(
      el,
      0.3,
      { y: 0, opacity: 1 },
      { y: -100, opacity: 0, onComplete: callback }
    );
  }

  componentWillAppear(callback) {
    console.log('appear');
  }

  render() {
    const { children, show } = this.props;
    return (
      <TransitionGroup component="div">
        <div ref={c => (this.container = c)}>
          {show && children}
        </div>
      </TransitionGroup>
    );
  }
}

And I am using it like this:

        <TransitionComponent transitionName="slide" show={expand}>
          <div>
            {children}
          </div>
        </TransitionComponent>

The life-cycle events are not being called.

Am I missing something?

cheapsteak commented 7 years ago

Ah, the lifecycle hooks need to go on the children components, not on the TransitionGroup component. That does seem to be a common point of confusion, I should update the docs.

Please give this article a skim: Animations with ReactTransitionGroup

And a solution for reusing animations - Reusing ReactTransitionGroup animations with Higher-order Components

dagda1 commented 7 years ago

Thanks, I have it working for the componentWillAppear but componentWIlLeave is not getting called.


export class Wrapper extends Component {
  props: Props;

  componentWillAppear(callback) {
    console.log('appear');
    const el = this.container;
    TweenMax.fromTo(
      el,
      1,
      { 'max-height': 0 },
      { 'max-height': '100vh', onComplete: callback }
    );
  }

  componentWillLeave(callback) {
    console.log('leave');
    const el = this.container;
    TweenMax.fromTo(
      el,
      0.3,
      { y: 0, opacity: 1 },
      { y: -100, opacity: 0, onComplete: callback }
    );
  }

  render() {
    return (
      <div ref={c => (this.container = c)}>
        {this.props.children}
      </div>
    );
  }
}

export class TransitionComponent extends Component {
  props: Props;

  render() {
    const { children } = this.props;
    return (
      <TransitionGroup>
        <Wrapper>
          {children}
        </Wrapper>
      </TransitionGroup>
    );
  }
}

TransitionComponent.displayName = 'TransitionComponent';

Should componentWillLeave not be called when componentWillUnmount is called?

cheapsteak commented 7 years ago

It looks like you have the animation lifecycle hooks in the <Wrapper>, and I assume you're conditionally displaying the children?

That wouldn't work because the lifecycle hook for componentWillLeave will only be called on the <Wrapper> when the <Wrapper> is removed, not when its children are. The actual components that are being added and removed need to have the lifecycle hooks on them

That is annoying from a code-reuse point of view, but take a look at the 2nd article I posted on how you could achieve something similar to using a Wrapper but with higher order components instead

cheapsteak commented 7 years ago

Oh btw there are examples of using this here: https://github.com/cheapsteak/react-transition-group-plus/tree/master/src/demo

Closing for now, let me know if you have any other questions :)