React - animate mount and unmount of a single component

前端 未结 16 1690
南笙
南笙 2020-12-22 16:34

Something this simple should be easily accomplished, yet I\'m pulling my hair out over how complicated it is.

All I want to do is animate the mounting & unmounti

16条回答
  •  梦毁少年i
    2020-12-22 17:07

    Here's how I solved this in 2019, while making a loading spinner. I'm using React functional components.

    I have a parent App component that has a child Spinner component.

    App has state for whether the app is loading or not. When the app is loading, Spinner is rendered normally. When the app is not loading (isLoading is false) Spinner is rendered with the prop shouldUnmount.

    App.js:

    import React, {useState} from 'react';
    import Spinner from './Spinner';
    
    const App = function() {
        const [isLoading, setIsLoading] = useState(false);
    
        return (
            
    {isLoading ? : }
    ); }; export default App;

    Spinner has state for whether it's hidden or not. In the beginning, with default props and state, Spinner is rendered normally. The Spinner-fadeIn class animates it fading in. When Spinner receives the prop shouldUnmount it renders with the Spinner-fadeOut class instead, animating it fading out.

    However I also wanted the component to unmount after fading out.

    At this point I tried using the onAnimationEnd React synthetic event, similar to @pranesh-ravi's solution above, but it didn't work. Instead I used setTimeout to set the state to hidden with a delay the same length as the animation. Spinner will update after the delay with isHidden === true, and nothing will be rendered.

    The key here is that the parent doesn't unmount the child, it tells the child when to unmount, and the child unmounts itself after it takes care of its unmounting business.

    Spinner.js:

    import React, {useState} from 'react';
    import './Spinner.css';
    
    const Spinner = function(props) {
        const [isHidden, setIsHidden] = useState(false);
    
        if(isHidden) {
            return null
    
        } else if(props.shouldUnmount) {
            setTimeout(setIsHidden, 500, true);
            return (
                
    ); } else { return (
    ); } }; export default Spinner;

    Spinner.css:

    .Spinner {
        position: fixed;
        display: block;
        z-index: 999;
        top: 50%;
        left: 50%;
        margin: -40px 0 0 -20px;
        height: 40px;
        width: 40px;
        border: 5px solid #00000080;
        border-left-color: #bbbbbbbb;
        border-radius: 40px;
    }
    
    .Spinner-fadeIn {
        animation: 
            rotate 1s linear infinite,
            fadeIn .5s linear forwards;
    }
    
    .Spinner-fadeOut {
        animation: 
            rotate 1s linear infinite,
            fadeOut .5s linear forwards;
    }
    
    @keyframes fadeIn {
        0% {
            opacity: 0;
        }
        100% {
            opacity: 1;
        }
    }
    @keyframes fadeOut {
        0% {
            opacity: 1;
        }
        100% {
            opacity: 0;
        }
    }
    
    @keyframes rotate {
        100% {
            transform: rotate(360deg);
        }
    }
    

提交回复
热议问题