1

Full code:
https://codesandbox.io/s/j4r7yoollw
I animate the modal on button click. But I want to be able to reverse the animation in components/Modal/index.css when I close it. I implemented setTimeout to give the modal time to fade out but it doesn't work. How do I do that so it does work?

Modal/index.js:

import React from 'react';
import Question from './Question';
import Loading from './Loading';
import Success from './Success';
import './index.css';

class Modal extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      success: false,
      reverse: false,
    };
  }
  removeUser = () => {
    this.setState({ loading: true });
    // simulate async loading action
    setTimeout(
      () =>
        this.setState({
          loading: false,
          success: true,
        }),
      2000,
    );
    //simulate promise (function above then this below)
    setTimeout(() => this.props.removeUser(this.props.data), 2001);
  };
  closeModal = () => {
    this.setState({ reverse: true });
    setTimeout(() => {
      this.props.closeModal();
      this.setState({
        reverse: false,
        success: false,
      });
    }, 3000);
  };
  render() {
    const { id, name } = this.props.data;
    const { loading, success } = this.state;
    // The gray background
    const backdropStyle = {
      position: 'fixed',
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      backgroundColor: 'rgba(0,0,0,0.3)',
      padding: 50,
    };

    // The modal "window"
    const modalStyle = {
      backgroundColor: '#fff',
      textAlign: 'center',
      borderRadius: 3,
      maxWidth: 360,
      minHeight: 130,
      margin: '0 auto',
    };

    if (this.props.displayModal) {
      return (
        <div className={'backdrop ' + (this.state.reverse ? 'reverse' : '')} style={backdropStyle}>
          <div className={'modal ' + (this.state.reverse ? 'reverse' : '')} style={modalStyle}>
            {!loading &&
              !success && (
                <Question
                  id={id}
                  name={name}
                  removeUser={this.removeUser}
                  closeModal={this.closeModal}
                />
              )}
            {loading && !success && <Loading />}
            {!loading && success && <Success closeModal={this.closeModal} />}
          </div>
        </div>
      );
    }
    return null;
  }
}

export default Modal;

Modal/index.css:

@keyframes modalFade {
  from {
    transform: translateY(-50%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.modal {
  animation-name: modalFade;
  animation-duration: 0.3s;
}

@keyframes backdropFade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.backdrop {
  animation-name: backdropFade;
  animation-duration: 0.3s;
}

.reverse {
  animation-direction: reverse;
}

4
  • 1
    Please provide code inside question Commented Oct 24, 2017 at 11:55
  • @artgb done, full code in codesandbox Commented Oct 24, 2017 at 11:59
  • 1
    Just noticed in Devtools that "reverse" is getting added to className, so I was wondering if it is the CSS that needs work? I am also learning. Commented Oct 24, 2017 at 12:22
  • @anand yes I think css animation is not started again when I just add class with animation-direction: reverse Commented Oct 24, 2017 at 12:27

1 Answer 1

1

I've made a few changes in your code and, as far as I tested, it's working fine.

In the css file, i've added a new animation for reverse modes to ensure the other animation, normal directioned, was canceled. I've also added animation-fill-mode: forwards; property to keep animation freezed on last frame.

In the jsx file, I've changed the timeout from 3000 to 300ms to match the animation duration 0.3s.

I've forked you at https://codesandbox.io/s/5wlooq88xl with those corrections.

closeModal = () => {
    this.setState({ reverse: true });
    setTimeout(() => {
      this.props.closeModal();
      this.setState({
        reverse: false,
        success: false,
      });
    }, 300);
  };
@keyframes modalFade {
  from {
    transform: translateY(-50%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

@keyframes modalFadeReverse {
  from {
    transform: translateY(0);
    opacity: 1;
  }
  to {
    transform: translateY(-50%);
    opacity: 0;
  }
}

.modal {
  animation-name: modalFade;
  animation-duration: 0.3s;
  animation-fill-mode: forwards;
}
.modal.reverse {
  animation-name: modalFadeReverse;
}

@keyframes backdropFade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes backdropFadeReverse {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.backdrop {
  animation-name: backdropFade;
  animation-duration: 0.3s;
  animation-fill-mode: forwards;
}
.backdrop.reverse {
  animation-name: backdropFadeReverse;
}

Sign up to request clarification or add additional context in comments.

1 Comment

Yes! Exactly what I was looking for! Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.