3

I am following this hackernoon guide https://hackernoon.com/animated-page-transitions-with-react-router-4-reacttransitiongroup-and-animated-1ca17bd97a1a in order to apply enter and leave animations to my react components when a route changes. I have obviously adapted the code to fit my site, and have decided not to use Animated but rather just pure CSS. Right now I'm just testing the code with console.log statements, and I noticed that componentWillEnter and componentWillLeave are not being called on route changes. Also, componentWillAppear only gets called once.

Here is the relevant code for each component, including App.js and index.js:

Animated Wrapper:

import React, {Component} from "react";
import styles from '../styles/AnimatedWrapper.css';

const AnimatedWrapper = WrappedComponent =>
  class AnimatedWrapper extends Component {
    componentWillAppear(cb) {
      console.log('componentWillAppear');
      cb();
    }
    componentWillEnter(cb) {
      console.log('componentWillEnter');
      cb();
    }
    componentWillLeave(cb) {
      console.log('componentWillLeave');
      cb();
    }
    render() {
      return (
        <div id="animated-wrapper" className={styles.animatedPageWrapper}>
          <WrappedComponent {...this.props}/>
        </div>
      );}
    };

export default AnimatedWrapper;

App.js:

import React, { Component } from 'react';
import { Route, Switch } from 'react-router-dom';
import TransitionGroup from "react-transition-group/TransitionGroup";

import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
import Slider from "./components/Slider";
import ComingSoon from "./components/ComingSoon";

const firstChild = props => {
  const childrenArray = React.Children.toArray(props.children);
  return childrenArray[0] || null;
}

class App extends Component {
  render() {
    return (
      <div className="App">
        <Navbar />
        <Switch>
          <Route
            path="/coming-soon"
            children={({ match, ...rest }) => (
              <TransitionGroup component={firstChild}>
                {match && <ComingSoon {...rest} />}
              </TransitionGroup>
          )}/>
          <Route
             path="/"
             children={({ match, ...rest }) => (
               <TransitionGroup component={firstChild}>
                 {match && <Slider {...rest} />}
               </TransitionGroup>
          )}/>
        </Switch>
        <Footer />
      </div>
    );
  }
}

export default App;

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import './index.css';

ReactDOM.render(
  <BrowserRouter>
     <App />
   </BrowserRouter>,
  document.getElementById('root')
);

Slider.js:

import React, { Component } from 'react';
import _ from 'lodash';

// components
import AnimatedWrapper from './AnimatedWrapper';
import Separator from './Separator';

// styles
import styles from '../styles/Slider.css';

// images
import Apartment from "../../public/images/apartment.jpg";
import Floor from "../../public/images/floor.jpg";
import Furniture from "../../public/images/furniture.jpg";
import Kitchen1 from "../../public/images/kitchen.jpg";
import Kitchen2 from "../../public/images/kitchen-2.jpg";

class SliderComponent extends Component {
  constructor(props) {
    super(props);

    this.state = {
      currentSlide: 0,
      slides: [Apartment, Floor, Furniture, Kitchen1, Kitchen2]
    };
  }

  componentDidMount() {
    this.zoomAnimation();
    this.slideContentAnimation();

    this.sliderInterval = setInterval(() => {
      if (this.state.currentSlide === 4) {
        if (this.refs.slider) {
          this.setState({ currentSlide: 0 });
        }
      } else {
        if (this.refs.slider) {
          this.setState({ currentSlide: this.state.currentSlide + 1 });
        }
      }
    }, 6000);
  }

  componentWillUpdate() {
    const currentContent = document.getElementById(`content-${this.state.currentSlide}`);
    setTimeout(() => {
      currentContent.classList.remove(`${styles.currentContent}`);
    }, 1500);
  }

  componentDidUpdate() {
    this.zoomAnimation();
    this.slideContentAnimation();
  }

  setSlide(number) {
    this.setState({ currentSlide: number });
  }

  zoomAnimation() {
    setTimeout(() => {
      const currentSlide = document.getElementById(`slide-${this.state.currentSlide}`);
      currentSlide.classList.add(`${styles.slideZoom}`);
    }, 500);
  }

  slideContentAnimation() {
    setTimeout(() => {
      const currentContent = document.getElementById(`content-${this.state.currentSlide}`);
      if (currentContent) {
        currentContent.classList.add(`${styles.currentContent}`);
      }
    }, 1500);
  }

  renderSlides() {
    return this.state.slides.map((slide, index) => {
      const isCurrent = index === this.state.currentSlide;

      const slideStyle = {
        backgroundImage: `url(${this.state.slides[index]})`
      }

      return (
        <div
          id={`slide-${index}`}
          key={`slide-${index}`}
          className={`
            ${styles.slide}
            ${isCurrent ? styles.currentSlide : null}
          `}
          style={slideStyle}
          alt="slide">
            <div
              id={`content-${index}`}
              key={`content-${index}`}
              className={`
                ${styles.content}
            `}>
              <h1>{`WE SPECIALIZE IN KITCHENS ${index}`}</h1>
              <Separator
                containerWidth={720}
                circleWidth={5}
                circleHeight={5}
                backgroundColor="#fff"
                lineWidth={350}
                lineColor="#fff"
              />
              <div
                className={`${styles['hvr-sweep-to-top']} ${styles.btn}`}>
                More Information
              </div>
            </div>
        </div>
      );
    });
  }

  renderNavBar() {
    return (
      <div className={styles.sliderNav}>
        {_.range(5).map((index) => {
          return (
            <div
              key={index}
              onClick={() => this.setSlide(index)}
              className={this.state.currentSlide === index ? styles.current : null}>
            </div>
          )
        })}
      </div>
    )
  }

  render() {
    return (
      <div className={styles.container} ref="slider">
        <div className={styles.slidesContainer}>
          {this.renderSlides()}
        </div>

        {this.renderNavBar()}
      </div>
    );
  }
}

const Slider = AnimatedWrapper(SliderComponent);
export default Slider;

ComingSoon.js:

import React from 'react';
import AnimatedWrapper from './AnimatedWrapper';
import styles from '../styles/ComingSoon.css';

const ComingSoonComponent = function() {
  return (
    <div>
      <div className={styles.mainContent}>
        <div>
          <h1 className={styles.mainTitle}>{`Coming Soon`}</h1>
        </div>
      </div>
    </div>
  );
};

const ComingSoon = AnimatedWrapper(ComingSoonComponent);
export default ComingSoon;

1 Answers1

-1

Try to Use react-transition-group, it will be help.

You can use it like this Example. As follow main code:

import { BrowserRouter, Route, Switch, Link } from 'react-router-dom'
import { CSSTransition, TransitionGroup } from 'react-transition-group'

const PageFade = (props) => (
  <CSSTransition 
    {...props}
    classNames="fadeTranslate"
    timeout={1000}
    mountOnEnter={true}
    unmountOnExit={true}
  />
)

const Layout = ({ children }) => (
  <section>
    <nav>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Non existing</Link></li>
      </ul>
    </nav>
    <hr />
    {children}
  </section>
)

const App = (props) => {
  const locationKey = props.location.pathname

  return (
  <Layout>
    <TransitionGroup>
      <PageFade key={locationKey}>
        <section className="fix-container">
          <Switch location={props.location}>
            <Route exact path="/" component={Home} />
            <Route exact path="/about" component={About} />
            <Route component={NotFound} />
          </Switch>
        </section>
      </PageFade>
    </TransitionGroup>
  </Layout>
  )
}

const BasicExample = () => (
  <BrowserRouter>
    <Route path="/" component={App} />
  </BrowserRouter>
);

render(<BasicExample />, document.getElementById('root'));
t Win
  • 171
  • 1
  • 5