2

I am trying to convert a pure JavaScript, CSS, and HTML animated navbar into a ReactJS component to use in a project.

The original code is written in HTML with a separate CSS styling file, and a JavaScript file which is linked to the HTML code via <script> tag. The below is a code snippet of my JavaScript file that I am trying to convert into ReactJS:

const navSlide = () => {
    const burger = document.querySelector('.burger');
    const navLinks = document.querySelectorAll('.nav-links li');

    burger.addEventListener('click', ()=> {

    navLinks.forEach((link, index) => {
        if (link.style.animation) {
            link.style.animation = '';
        } else {
            link.style.animation = 'navLinkFade 0.5s ease forwards $(index / 7 + 1}s
        }
    });
}
navSlide();

The ReactJS component that I am trying to change to accommodate the above code snippet currently contains the following code:

import React, { useState } from "react";

const NavBar = () => {
  const [navOpened, setNavOpened] = useState(false);
  const navClassNames = navOpened ? "nav-links nav-active" : "nav-links";

  return (
    <div className="navbar">
      <nav>
        <div className="logo">
          <h4>Reuben McQueen</h4>
        </div>
        <ul className={navClassNames}>
          <li>
            <a href="#">Projects</a>
          </li>
          <li>
            {" "}
            <a href="#">Experiments</a>
          </li>
          <li>
            {" "}
            <a href="#">Skills</a>
          </li>
          <li>
            {" "}
            <a href="#">Contact Me</a>
          </li>
        </ul>
        <div className="burger" onClick={() => setNavOpened(!navOpened)}>
          <div className="line1" />
          <div className="line2" />
          <div className="line3" />
        </div>
      </nav>
    </div>
  );
};

export default NavBar;

The CSS for .nav-links li is the following:

.nav-links li {
    list-style: none;
}

The code should individually move in each list item after the time delay is given.

double-beep
  • 5,031
  • 17
  • 33
  • 41

1 Answers1

2

You should be able to map over your navlinks and apply styles to them (or lack thereof) depending upon the drawer state.. Something like this simulates what you are after, I believe..

EDIT: I updated my answer to something a little more efficient...

ORIGINAL ANSWER:

const NavBar = () => {
  const [navOpened, setNavOpened] = React.useState(false);
  const navLinks = ["One", "Two", "Three"];
  const handleBurgerClick = () => {
    setNavOpened(!navOpened);
  }
  
  return (
    <div>
      <div onClick={handleBurgerClick} className="burger">BURGER {navOpened ? "(close " : "(open "}me)</div>
      <ul className="nav-links">
        {navOpened
          ? navLinks.map((nl, index) => {
              return (
                <li
                  style={{
                    animation: `navLinkFade 0.5s ease forwards ${index / 7 + 0.1}s`
                  }}
                >
                  Link {nl}
                </li>
              );
            })
          : ""}
      </ul>
    </div>
  );
};

ReactDOM.render(<NavBar />, document.body);
.burger {
  cursor: pointer;
  text-align: center;
  width: 80px;
}

.burger:hover {
  color: blue;
}

.nav-links li {
  list-style: none;
  opacity: 0;
}

@keyframes navLinkFade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

MORE ADVANCED ANSWER (lets you fade in AND out)

const NavBar = ({ navLinks = [] }) => {
  const [navOpened, setNavOpened] = React.useState(false);
  const [styles, setStyles] = React.useState({ opacity: 0 });
  
  const handleBurgerClick = () => {
    setStyles(
      navOpened ? { name: 'navLinkFadeOut' } : { opacity: 0, name: 'navLinkFadeIn' }
    );
    setNavOpened(!navOpened);
  }
  
  const oppositeIndex = (arr, index) => arr.indexOf([...arr].reverse()[index]);
  
  const getDelay = index => (navOpened ? index : oppositeIndex(navLinks, index)) / 7 + 0.1;
  
  const getStyle = index => {
    return styles.name ? {
      ...styles, 
      animation: `${styles.name} 0.5s ease forwards ${getDelay(index)}s` 
    } : styles;
  }
  
  return (
    <div>
      <button onClick={handleBurgerClick} className="burger">
        BURGER {navOpened ? "(close " : "(open "}me)
      </button>
      <ul className='nav-links'>
        {navLinks.map((e, i) => <li style={getStyle(i)}>{e}</li>)}
      </ul>
    </div>
  );
};

ReactDOM.render(
  <NavBar navLinks={["One", "Two", "Three"]} />, 
  document.body
);
.burger {
  cursor: pointer;
  text-align: center;
  width: 140px;
  height: 25px;
}

.burger:hover {
  color: blue;
}

.nav-links li {
  list-style: none;
}

@keyframes navLinkFadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes navLinkFadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
Matt Oestreich
  • 8,219
  • 3
  • 16
  • 41