Hi there everyone!
Quick Context
I've recently been working on a feature that includes a bit of animation, alongside some design system classes. I wanted to introduce hooks into the code base for the first time, and decided to give it a try!
Challenge
There were two challenges I had when using animations for fading out:
- An element would re-appear after the fadeOut animation without applying a second class to hide it
- When applying a hidden class at the same time as an animation class, the animation didn't happen - just the disappearing :).
Solution
To solve this, I utilized a useEffect() hook which would set the animation class, followed by a setTimeout with a 1-second delay, to first complete the animation and then successfully hide the element we are animating.
I utilized the return function of hooks to clean up any timers on the element to prevent memory leaks.
Below you can see the code I've written (shortened version) to solve the challenge, or you can check out this Code Pen.
if you want to see the issue, comment out the useEffect hook and you will see that it fades out, then comes right back into view!
The isHidden
prop is passed down from a higher component, which changes based on a tap/click.
Code
React
export const SomeNavHeader = ({
title = 'Some Title',
isHidden
planId
}) => {
const TOPBAR_VISIBILITY_CLASSES = {
hidden: 'hide',
visible: ''
}
const ANIMATION_CLASSES = {
fadeIn: 'fade-in',
fadeOut: 'fade-out'
}
// set default state to use fade in and visible class
const [animationClass, setAnimationClass] = useState(ANIMATION_CLASSES.fadeDownAndIn)
const [topbarNavHiddenClass, setTopbarNavHiddenClass] = useState(TOPBAR_VISIBILITY_CLASSES.visible)
// this will run everytime isHidden changes
useEffect(() => {
// set timer ids to null to help with clean up - null is OK here
let hiddenClassTimer = null
if (isHidden) {
// fade out then hide once animation finishes
setAnimationClass(ANIMATION_CLASSES.fadeOut)
hiddenClassTimer = setTimeout(() => {
setTopbarNavHiddenClass(TOPBAR_VISIBILITY_CLASSES.hidden)
}, DELAYS_IN_MS.oneSecond)
} else {
// show topbar and animate it in
setAnimationClass(ANIMATION_CLASSES.fadeIn)
setTopbarNavHiddenClass(TOPBAR_VISIBILITY_CLASSES.visible)
}
// return function helps to clean up timeouts if they are happening when component is removed from dom
return () => {
clearTimeout(hiddenClassTimer)
}
}, [
isHidden
])
return (
<header
className={`some-header-component ${DESIGN_SYS.topBar} ${
DESIGN_SYS.color.neutral90
} ${animationClass} ${topbarNavHiddenClass}`}
>
<p>{title}</p>
</header>
)
}
Scss
.some-header-component {
&.fade-in {
animation-duration: 1s;
animation-name: fadeIn;
}
&.fade-out {
animation-duration: 1s;
animation-name: fadeOut;
}
&.hide {
display: none;
}
}
Is There a Better Way?
I'd absolutely love feedback or other suggestions on the best way to handle the given challenge!
Please let me know if you have any questions!