reactjs / react-transition-group

An easy way to perform animations when a React component enters or leaves the DOM
https://reactcommunity.org/react-transition-group/
Other
10.14k stars 651 forks source link

Exiting animation not firing even when in set to false and passed as props #405

Closed adamwright104 closed 6 years ago

adamwright104 commented 6 years ago

https://codesandbox.io/s/qxk1wv69j4

i've added the code above, the styles aren't coming through but you have all the files.

So i have a few nested elements in a main transition for the page.

The whenInView.js component animates in using waypoint to detect when in view, this works fine and i'm then triggering the exiting and exit events when a user clicks the image.

This the fires and event on the main App.js file which updates the global state that holds the value for the transition property "in" (true or false)

This is passed to the header.js component but when its changes in whenInView.js the header component never gets updated. Am i missing something or just done this wrong:

Any pointers on the code would be great as i'm not sure this is a good way of doing it.

many thanks

jquense commented 6 years ago

any chance you can trim this down to just the Transition code and the resulting bug?

adamwright104 commented 6 years ago

@jquense managed to fix it, i had missed the gsap duration of the exiting animation in the header.js. i also had to remove the TransitionGroup around it and then call componentWillReceiveProps to force the changes

import React, { Component } from "react";
import { Link } from "react-router-dom";
import { TweenLite, TweenMax } from "gsap";
import { Transition } from "react-transition-group";
import styles from "./Header.scss";

class Header extends Component {
  constructor(props) {
    super(props);
    this.state = {
      in: this.props.in,
    };
  }

  onExiting(node) {
    console.log('exiting header')
    TweenMax.killTweensOf(node);
    TweenLite.to(node, 0.5, {
      y: "-200px",
      onCompleteParams: [node],
    });
  }

  componentWillReceiveProps(nextProps) {
    if(nextProps.in !== this.props.in) {
      this.setState({
        in: nextProps.in
      })
    }
  }

  render() {
    const show = this.state.in
    return (
      <Transition
        timeout={2000}
        appear={true}
        in={show}
        onEnter={node => {
          // first kill all tweens of the target
          TweenMax.killTweensOf(node);
          TweenLite.set(node, {
            y: "-200px",
            onCompleteParams: [node],
          });
          // animate in the element
          TweenLite.to(node, 0.5, {
            y: "0px",
            delay: 0.5,
            onCompleteParams: [node]
          });
        }}
        onExiting={node => {
          this.onExiting(node)
        }}
      >
         <div>
            <a href="#main-content" className="u-visually-hide">
              Skip to content
            </a>
            <nav className={`${styles.navbar} js-navigation`}>
              <div className="container">
                <div className="row">
                  <div className={styles.wrapper}>
                    <Link to="/" className={styles.brand}>
                      Adam Wright - {JSON.stringify(show)}
                    </Link>

                      <div className={styles.links}>
                        <ul className={styles.list}>
                          <li className={styles.item}>
                            <a
                              href=""
                              className={styles.link}
                              onClick={e => this.props.toScroll(e, "#about")}
                            >
                              About
                            </a>
                          </li>
                          <li className={styles.item}>
                            <a
                              href=""
                              className={styles.link}
                              onClick={e => this.props.toScroll(e, "#work")}
                            >
                              Work
                            </a>
                          </li>
                          <li className={styles.item}>
                            <a
                              href=""
                              className={styles.link}
                              onClick={e => this.props.toScroll(e, "#contact")}
                            >
                              Contact
                            </a>
                          </li>
                        </ul>
                      </div>
                  </div>
                </div>
              </div>
            </nav>
          </div>
      </Transition>
    );
  }
}

export default Header;

i'm still confused by the TransitionGroup and the timeout. am i using this in the right way?

Update: i'm trying to create page transitions like on this site http://www.buildinamsterdam.com/

silvenon commented 6 years ago

I might have an answer to both of your questions:

I'm closing this because I don't think it indicates any problem with RTG.

Btw, if this RTG + GSAP integration is overwhelming to you, a little birdie told me that @rhernandog is writing a RTG + GSAP guide. I'm not sure if that's finished yet, but you should give it a read when it's done.

adamwright104 commented 6 years ago

@silvenon thanks. i've added work in progress to a surge domain http://react-transition-group-test.surge.sh/