I am using the react transition group library to apply a slide down fade animation to the navbar 1 second after the page loads, the main issue falls on elements that are nested in a .map function while the rest render just fine. This is how my navComponent looks like (with comments):
const Navbar = () => {
//This code right here handles the visibility of the navbar on scrolldown/scrollup
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
const handleScroll = () => {
const currentScrollPos = window.scrollY;
setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10);
setPrevScrollPos(currentScrollPos);
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [prevScrollPos, visible]);
//Fade animations ***HERE IS THE ISSUE (I think)***//
//Hold state in order to mount the element after timer
const [isMounted, setIsMounted] = useState(false);
//Creates a timer to set "isMounted" after 1000ms
useEffect(() => {
const timeout = setTimeout(() => {setIsMounted(true)}, 1000);
return () => clearTimeout(timeout)
}, [])
//Elements and their Refs to be used with CSSTransitions
const logoRef = useRef()
const logo = (
<div className='logo' ref={logoRef} style={{ transitionDelay: `100ms` }}>
<p>RAUNCHO</p>
</div>
);
//All li elements have these <Link> attributes, however for code readability purposes I will only leave them for 'li1', the rest will be deleted
const li1Ref = useRef();
const li1 = (
<li className="navbar-item">
<Link
className='navLink-item'
activeClass="active"
to="about"
spy={true}
smooth={true}
offset={0}
duration={500}>
<span id='codeFont'>01.</span>
About
</Link>
</li>
)
const li2Ref = useRef();
const li2 = (
<li className="navbar-item">
<Link>
<span id='codeFont'>02.</span>
Experience
</Link>
</li>
)
const li3Ref = useRef();
const li3 = (
<li className="navbar-item">
<Link>
<span id='codeFont'>03.</span>
Projects
</Link>
</li>
)
const li4Ref = useRef();
const li4 = (
<li className="navbar-item">
<Link>
<span id='codeFont'>04.</span>
Contact
</Link>
</li>
)
const li5Ref = useRef();
const li5 = (
<li className="navbar-item">
<button className='CTA-button' id="resume">
Resume
</button>
</li>
)
//Element array to iterate through
const navElements = [[li1,li1Ref],[li2,li2Ref],[li3,li3Ref],[li4,li4Ref],[li5,li5Ref]]
return (
<nav className={`navbar ${visible ? 'visible' : 'hidden'} ${prevScrollPos <= 10 ? 'at-top' : ''}`}>
<TransitionGroup component={null}>
{isMounted && (
<>
//Logo element renders just fine
<CSSTransition in={isMounted} nodeRef={logoRef} classNames="fade" timeout={1000}>
{logo}
</CSSTransition>
//As mentioned above, li elements are rendered first at once in the DOM, then the animations are applied
<ul className="navbar-list">
{navElements.map(([navLi,ref], i) => {
return (
<CSSTransition key={i} in={isMounted} classNames="fadedown" timeout={1000} nodeRef={ref}>
<span style={{ transitionDelay: `${i + 1}00ms`}} ref={ref}>
{navLi}
</span>
</CSSTransition>
)
})}
</ul>
</>
)}
</TransitionGroup>
</nav>
);
};
export default Navbar;
Here is the CSS for fade/fadedown/navbar:
/*fade styles*/
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms ease-in-out;
}
/*fadedown styles*/
.fadedown-enter {
opacity: 0.01;
transform: translateY(-20px);
transition: opacity 300ms ease-in-out, transform 300ms ease-in-out;
}
.fadedown-enter-active {
opacity: 0.01;
transform: translateY(-20px);
transition: opacity 300ms ease-in-out, transform 300ms ease-in-out;
}
.fadedown-enter-done {
opacity: 1;
transform: translateY(0px);
transition: opacity 300ms ease-in-out, transform 300ms ease-in-out;
}
/*NAVBAR*/
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px 40px;
z-index: 10;
/*slide on scroll up animation*/
transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
background-color: rgba(10, 25, 47, 0.5);
backdrop-filter: blur(10px);
}
.visible {
transform: translateY(0);
opacity: 1;
position: sticky;
top: 0;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.2);
}
.visible.at-top {
box-shadow: none;
}
.hidden {
transform: translateY(-100%);
opacity: 0;
position: sticky;
top: 0;
}
.logo {
font-size: 20px;
font-weight: bold;
color: var(--primary-font-color);
}
.navbar > ul {
display: flex;
align-items: center;
list-style: none;
font-size: 14px;
}
.navbar-list li:last-child {
margin-left: 25px;
}
.navLink-item {
color: var(--primary-font-color);
margin: 0px 10px;
font-family: 'Roboto Mono', monospace;
}
.navLink-item:hover {
color: var(--code-font-color);
cursor: pointer;
transition: color .3s;
}
Here are some pictures about the nature of the problem
1st - it loads all the elements at once as soon as 'isMounted' changes to 'true'
2nd - it applies the classes fromCSSTransitions causing the transition to play backwards elements fade away and dissapear
3rd - it plays the animation as it should elements fade down as they should