How to prevent animation on initial render?
Asked Answered
D

3

6

I have a component that has dynamic class names based on the state of the component. The initial state of the menu component is false so an exit animation triggers when I load the site. I'm trying to not play the exit animation on initial render, I'm trying to trigger the animation only when the user clicks away from the menu.

@keyframes menuEnter {
    from {
        transform: translateY(-100vh);
    }
    to {
        transform: translateY(0);
    }
}

@keyframes menuExit {
    from {
        transform: translateY(0);
    } 
    to {
        transform: translateY(-100vh);
    }
}
const [showMenu, setShowMenu] = useState(false)
<div className={`menuContainer ${showMenu ? `menuEnter` : 'menuExit'}`} id='menu'>

I'm trying to bail out of the exit animation because it doesn't make sense to play the exit animation on initial render.

The state changes onClick, when state is true onClick sets it to false and when state is false the onClick sets it to true.

Detoxicate answered 29/8, 2020 at 17:18 Comment(2)
you need to rethink the conditions. You should add menuExit only if your menu is opened. And also add the classes on an event triggered by your menu trigger ( hover, click whatever )Girosol
Edited my question. What would be another way dealing with the conditions?Detoxicate
J
5

The javascript is okay, it's the CSS that needs fixing. Instead of using animations, just use transitions so the menu doesn't go from open to close on render.

Try the following:

Add a transition to your menu id:

#menu {
    transition: 0.3s ease-out;
}

Then change this value by switching between a menu open and close class:

 .menuEnter {
    transform: translateY(0);
}

 .menuExit {
    transform: translateY(-100vh);
}

That way, when the component renders, the menu doesn't go from one animation state to another, it remains closed.

PS: Consider using 3d transforms for performance reasons.

Jephthah answered 29/8, 2020 at 17:44 Comment(0)
C
0

You can achieve this by defaulting showMenu to undefined,

const [showMenu, setShowMenu] = useState(undefined)
<div className={`menuContainer ${showMenu ? `menuEnter` : showMenu === undefined ? '' : 'menuExit'}`} id='menu'>
Corniculate answered 3/11, 2023 at 15:19 Comment(0)
M
0

I had same issue and I ended up adding transition class to onClick before menu gets opened or closed:

const { useState,useEffect } = React

const Example = () => {
  const [showMenu, setShowMenu] = useState(false)
  const [menuMounted, setMenuMounted] = useState(false)
  const mountedClass = menuMounted ? 'mounted' : ''
  const showMenuClass = showMenu ? 'menuOpen' : 'menuClosed'
  
  useEffect(() => {
    // imitate redux state change
    setTimeout(() => setShowMenu(true), 2000)
  }, [])
  
  return (
    <>
      <button onClick={() => {
        setMenuMounted(true)
        setShowMenu(!showMenu)
      }}>Toggle</button>
      <div className={`menuContainer ${showMenuClass} ${mountedClass}`}>
        1<br/>1<br/>1<br/>1<br/>1<br/>1<br/>
      </div>
    </>
  )
}

ReactDOM.createRoot(document.getElementById("root")).render(
  <Example />
)
.menuContainer {
  overflow: hidden;
}

.mounted {
  transition:
    height 0.3s ease-in-out,
    box-shadow 0.1s linear;
}

.menuClosed {
  height: 0;
}

.menuOpen {
  height: 110px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Mikaela answered 20/10 at 11:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.