Hello everyone,
since recently I started using React with GSAP. I have little experience in both, so the struggle is real.
I am trying to create something very simple, a full screen menu that you can show/hide.
When i am trying to debug this, i can see the state changing, and if I try to print within the `toggleMenu()`, method, i can see the state is changing however `timeline.play()`, simply doesn't do anything. I tried also removing the if case for play and reverse but still no effect. Its just atht my timeline doesnt want to play.
I also tried using `componentDidUpdate()` but still no success.
in that case my code looked like this:
toggleMenu() {
this.setState({
visible: !this.state.visible
});
}
componentDidUpdate(prevProps, prevState){
const {visible: preVisible} = prevState;
const { visible } = this.state;
if (visible && visible !== preVisible) {
this.timeline.play();
}
}
componentDidMount(){
this.timeline = new TimelineLite({ paused: true })
.to(this.menuRef.current, 0.5, {autoAlpha: 1});
// .staggerTo(this.listNodes, 0.3, { opacity: 1,y: 0}, 0.2, "-=0.3");
}
This is my container, where the magic is supposed to happen:
import React, { Component } from "react";
import Hamburger from "./hamburger.jsx";
import Menu from "./menu.jsx";
import Logo from "./misc/Logo.jsx";
import { TweenMax, TimelineLite, CSSPlugin } from "gsap/all";
import { Transition } from "react-transition-group";
class MenuContainer extends Component {
constructor(props) {
super(props);
this.state = {
visible: false
};
this.toggleMenu = this.toggleMenu.bind(this);
this.timeline = null;
this.menuRef = React.createRef();
}
toggleMenu() {
console.log(this.state.visible)
this.state.visible ? this.timeline.reverse() : this.timeline.play();
this.setState({
visible: !this.state.visible
});
}
componentDidMount(){
this.timeline = new TimelineLite({ paused: true })
.to(this.menuRef.current, 0.5, {autoAlpha: 1});
// .staggerTo(this.listNodes, 0.3, { opacity: 1,y: 0}, 0.2, "-=0.3");
}
render() {
const { visible } = this.state;
let logoColor = "#3e444e"; //blue
if (visible) logoColor = "#ffffff"; //White
return (
<div className="nav-wrapper">
<div className="top-bar">
<div className="top-bar-left">
<Logo logocolor={logoColor} />
</div>
<div className="top-bar-right">
<div>
<Hamburger
handleMouseDown={this.toggleMenu}
menuVisibility={visible}
/>
</div>
</div>
</div>
<div>
<Menu visible={visible} menuRef={this.menuRef} />
</div>
</div>
);
}
}
export default MenuContainer;
This is the menu element where I am setting the `ref`:
import React, { Component } from "react";
import { apiUrl } from './../../methods';
class Menu extends Component {
constructor(props) {
super(props);
this.state = {
links: [],
isLoading: false,
error: null
};
}
componentDidMount() {
const targetUrl = apiUrl("/sapi/main_menu_items.json");
this.setState({ isLoading: true });
fetch(targetUrl)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error("Something went wrong....");
}
})
.then(data => this.setState({ links: data.links, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false })); //Passing the data to state.links and changing isLoading to false
}
render() {
const { links, isLoading, error } = this.state;
const listItems = links.map((link, index) => (
<li
className="menu-link v-link"
key={link.slug}
// ref={li => (this.listNodes[index] = li)}
>
<a href={link.slug}>{link.title}</a>
</li>
));
if (error) return <p>{error.message}</p>;
if (isLoading) return <p>Loading....</p>;
return (
<div className="full-screen-menu" ref={this.props.menuRef}>
<div className="grid-y grid-frame align-middle">
<div className="cell auto links-wrapper">
<div className="grid-container full-height">
<div className="grid-x align-middle full-height">
<div className="cell small-12">
<ul className="links">{listItems}</ul>
</div>
</div>
</div>
</div>
<div className="cell shrink">
<div className="grid-container">
<div className="grid-x">
<div className="cell small-12 text-right text-white">
<ul>
<li>
<a className="text-white">+31 638 501 270</a>
</li>
<li>
<a className="text-white">hello@whale-agency.com</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Menu;
And here is the hamburger, that is being clicked:
import React, { Component } from "react";
import MenuOpener from "./misc/menuOpener.jsx";
import MenuCloser from "./misc/menuCloser.jsx";
class Hamburger extends Component {
render() {
if (!this.props.menuVisibility) {
return (
<MenuOpener
className="menu-button"
onMouseDown={this.props.handleMouseDown}
/>
);
} else {
return (
<MenuCloser
className="menu-button"
onMouseDown={this.props.handleMouseDown}
/>
);
}
}
}
export default Hamburger;
Last but not least, the important css:
.full-screen-menu {
position: absolute;
opacity: 0;
visibility: hidden;
width: 100vw;
height: 100vh;
bottom: 0;
left: 0;
background: url(/images/menu-background.jpg);
background-size: cover;
background-position: center;
background-repeat: no-repeat;
z-index: 999;
}
Hopefully someone can help me go in the right direction.
Greetings,
Nikolay