reactjscss-animationsreact-transition-groupweb-animationsreact-animations

React v17.0.1 - How can an animation be triggered when a div comes into viewport?


I am working on a web-app which I'm building by using React.js. I want to trigger an animation when the div comes into the viewport. Currently, I am able to run the animations but the animations don't wait for the div to enter the viewport.

Let us say a user accesses the site and switches to another tab before the components have been mounted. So, before the user switches back to this tab, let us say the components are mounted but the animation should start only once the user switches back to this tab.

I have implemented the animations using CSSTransitionGroup from react-transition-group package. I am trying to figure out how I can make the animations trigger when the div has entered the viewport.

RequestFormComponent.js

const RequestForm = (props) => {

  const handlesubmit = ()=> {
  ///
  }
  return (
        <>
            <Jumbotron style={{ backgroundImage: './images/jumbo.jpg'}}>
                <div className="container">
                   <div className="row">
                      <CSSTransitionGroup
                         transitionName="request-form"
                         transitionAppear={true}
                         transitionAppearTimeout={1000}
                         transitionEnter={false}
                         transitionLeave={false}
                         transitionEnterTimeout={1000}
                         transitionLeaveTimeot={300}
                         >
                            <div className="request_form">
                               <h4>Create a request</h4>
                                  <Form id="create-request" model="request" onSubmit={(values) => handleSubmit(values)}>
                                     ///
                                  </Form>
                            </div>
                         </CSSTransitionGroup>
                     </div>
                </div>
            </Jumbotron>

        </>
    )
}

export default RequestForm;

CSS

.request-form-appear.request-form-appear-active {
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-iteration-count: 1; 
  animation-name: slideInFromRight;
}

I know this can be achieved by using JQuery but is there a way to achieve it by using only React.js? Even if there is a work around for this using JQuery with React, please give your suggestions.

Thanks for the help!


Solution

  • There is an npm-package called "react-in-viewport" which can be used to detect whether a component is in the viewport or not. The props inViewport and enterCount are useful in my case. I can display the animation when the component is in the viewport for the first time. Following condition can be used:

    if(inViewPort && enterCount === 1){
       //
    }
    

    The documentation and demo provide sufficient information on using the package. The complete implementation is given below:

    import handleViewport from 'react-in-viewport';
    
    const Block = (props) => {
        const { inViewport, forwardedRef, enterCount } = props;
        if (inViewport && enterCount === 1) {
            return (
                <div ref={forwardedRef}>
                    <div className="container">
                        <div className="try" style={{ backgroundColor: "teal", height: '20vh' }}>
                            <span>Wanna Send goods to your loved ones?</span>
                        </div></div>
                </div>
            )
        }
        return (
            <div ref={forwardedRef}>
                <div className="container">
                    <div className="try-static" style={{ backgroundColor: "teal", height: '20vh' }}>
                        <span>Wanna Send goods to your loved ones?</span>
                    </div></div>
            </div>
        );
    };
    
    const ViewportBlock = handleViewport(Block, /** options: {}, config: {} **/);
    
    const Component = (props) => (
        <div>
            <div style={{ height: '100vh' }}>
                <h2>Scroll down to make component in viewport</h2>
            </div>
            <ViewportBlock onEnterViewport={() => console.log('enter')} onLeaveViewport={() => console.log('leave')} />
        </div>
    )
    
    export default Component;
    

    CSS

    .try{
      animation-duration: 1s; 
      animation-timing-function: linear; 
      animation-delay: 0s; 
      animation-iteration-count: 1; 
      animation-name: slideInFromBottom; 
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      margin-left: auto;
      margin-right: auto;
      width: 50%;
      transform: translateY(-50%);
      color: white;
    }
    
    .try-static{
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      margin-left: auto;
      margin-right: auto;
      width: 50%;
      transform: translateY(-50%);
      color: white;
    }