DEV Community

loading...
Cover image for React Simplified: Infield Example of React Hooks ft. Hamburger Navigation Pt. 2

React Simplified: Infield Example of React Hooks ft. Hamburger Navigation Pt. 2

uzomezu profile image Kevin Mezu Updated on ・5 min read

Hey there! If you haven't seen Part 1: Vanilla JS Hamburger Menu, please check it out before reading this.

In Part 1 we created a simple hamburger Nav-bar using HTML, CSS, and JavaScript.

Alt Text

This code was very simplistic, however what happens when we need to make a larger file? When we need to change several states from closed to open? Changing visibility is simple with display property, but more elements means we need more variables, functions, and time!

React.js and create-react-app offers a brilliant solution using state hooks, and Babel syntax. By leveraging npm packages, and the structure of a React.js app we can shorten our code and create reusable solutions!

Steps: create-react-app

In VS-Code or your windows/mac cmd(terminal), please cd into the project folder. I named mine hamburger-nav but anything will work. Be aware the next steps require the latest version of Node.js and npm. So, Click here and do that first before continuing.
Enter

npm --v

and

node --v

to ensure latest version was installed.


In the command prompt type the following

npm i -g create-react-app 

Enter fullscreen mode Exit fullscreen mode

Wait for the install to finish than type:

npx create-react-app client
Enter fullscreen mode Exit fullscreen mode

This command installs all react.js scripts and the react command line interface. Next you want to enter the client folder with:

cd client
npm install
npm start
Enter fullscreen mode Exit fullscreen mode

Alt Text

Navigate to https://localhost:3000 and the above screen will show.


As we saw in part one our file consisted of a HTML file with some JavaScript inside:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
 <button class="menu-btn">&#9776;</button>
  </nav>
  <aside class="overlay-menu">
    <div>
      <a href="">Home</a>

    </div>
    <div>
      <a href="">Shop</a>
    </div>
    <div>
      <a href="">Contact</a>
    </div>
    <div>
      <a href="">Help</a>
    </div>
  </aside>
  <script>
    (function () {
  const menuBtn = document.querySelector(".menu-btn");
  const menuOverlay = document.querySelector(".overlay-menu");
  let menuOpen = false;

  menuBtn.addEventListener("click", () => {
    if (!menuOpen) {
      menuBtn.innerHTML = "X";
      menuOverlay.style.display = "flex";
      menuOpen = true;
    } else {
      menuBtn.innerHTML = "&#9776;"; //decimal for hamburger icon
      menuOverlay.style.display = "none";
      menuOpen = false;
    }
  });
})();
  </script>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

We are going to start by substituting all of this messy HTML with npm packages inside the App.js document of react.

First install the elements needed for bootstrapping HTML.

npm i react-bootstrap bootstrap

Enter fullscreen mode Exit fullscreen mode

Then go into the App.js file and make it look like this:

import './App.css';
import React, {useState} from 'react';
import { Navbar, Button } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
const bars = <i class="fa fa-bars"></i>;
const xMark = <i class="fa fa-times" aria-hidden="true"></i>;
const links = ['home', 'shop', 'contact', 'help'];
function App() {

  return (
   <>
    <Navbar bg="dark" variant="dark">
         <Button className="menu-btn" variant="light" onClick={}> 
            </Button>
         </Navbar>

    <aside className="overlay-menu">
      {links.map(link =>(
        <div>
          <a href={"/"+link}>{link}</a>
        </div>
      ))}
      </aside>
  </>
  );
}
export default App;

Enter fullscreen mode Exit fullscreen mode

Vanilla JS to React

The benefit of react is in using inbuilt functions like useState. This is a Hook which basically means it hooks the HTML components and alters their structure based on the state of the DOM.

This is accomplished by simply using the format:

const [state, setState] = useState(false)

Enter fullscreen mode Exit fullscreen mode

we have:
1.created a mutable value for the state
2.a callback function to setState
3.inital value of false for the beginning circumstance

Let's imagine this for our own circumstances as


const [menuOpen, setMenuOpen] = useState(false) // menu not open

Enter fullscreen mode Exit fullscreen mode

Ahah! Now we see how the condition of open menu and closed is now accessible through one function of setMenuOpen(Boolean) according to our states.

Add some helper functions:

 const openMenu = () =>{
        menuOverlay.style.display = "flex";
        setMenuOpen(true);
  }
  const closeMenu = () => {
        menuOverlay.style.display = "none";
        setMenuOpen(false)
  }
Enter fullscreen mode Exit fullscreen mode

Great! Now we need to initialize these functions in our JSX. Usually we would have to wrap our code in an event listener and some conditional statement.

However React uses ESLint/Babel Syntax, which is a special coding syntax of JavaScript that compiles into something the browser can read.

With JSX, we can easily place our if/else statements within the JSX as so:

<Button 
className="menu-btn" 
variant="light" onClick={menuOpen === false ? openMenu : closeMenu}> 
           {menuOpen === false : bars : xMark}
//place fontawesome cdn inside /public/index.html
//This will activate the fontawesome classes
            </Button>

Enter fullscreen mode Exit fullscreen mode

Now our crustier JavaScript From before (49 Lines):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>
<body>
<nav class="navbar navbar-dark bg-dark">
 <button class="menu-btn">&#9776;</button>
  </nav>
  <aside class="overlay-menu">
    <div>
      <a href="">Home</a>

    </div>
    <div>
      <a href="">Shop</a>
    </div>
    <div>
      <a href="">Contact</a>
    </div>
    <div>
      <a href="">Help</a>
    </div>
  </aside>
  <script>
    (function () {
  const menuBtn = document.querySelector(".menu-btn");
  const menuOverlay = document.querySelector(".overlay-menu");
  let menuOpen = false;

  menuBtn.addEventListener("click", () => {
    if (!menuOpen) {
      menuBtn.innerHTML = "X";
      menuOverlay.style.display = "flex";
      menuOpen = true;
    } else {
      menuBtn.innerHTML = "&#9776;"; //decimal for hamburger icon
      menuOverlay.style.display = "none";
      menuOpen = false;
    }
  });
})();
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

can be transformed into a sleeker more intuitive reactJS app (35 Lines of code)

import './App.css';
import React, {useState} from 'react';
import { Navbar, Button } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
const links = ['home', 'shop', 'contact', 'help'];
function App() {
  const bars = <i class="fa fa-bars"></i>;
  const xMark = <i class="fa fa-times" aria-hidden="true"></i>;
  const [menuOpen, setMenuOpen] = useState(false);
  const menuOverlay = document.querySelector(".overlay-menu"); 
  const openMenu = () =>{
        menuOverlay.style.display = "flex";
        setMenuOpen(true);
  }
  const closeMenu = () => {
        menuOverlay.style.display = "none";
        setMenuOpen(false)
  }
  return (
    <>
    <Navbar bg="dark" variant="dark">
         <Button className="menu-btn" variant="light" onClick={menuOpen===false ? openMenu : closeMenu}>{menuOpen === false ? bars : xMark}</Button>
  </Navbar>

    <aside className="overlay-menu">
      {links.map(link =>(
        <div>
          <a href={"/"+link}>{link}</a>
        </div>
      ))}
      </aside>
  </>
  );
}
export default App;

Enter fullscreen mode Exit fullscreen mode

react-app-nav-bar
And Voilà! Same results; 14 less lines of code (49-35 = 14).

Recap

I learned 3 great points from this exercise:

1. Always create a vanilla js template before jumping into a framework.

2. Less is more: It is easier to delete than to add lines of code.

3. React is meant to be bootstrapped, use your resources!!!

I thoroughly enjoyed learning the concept of react hooks using a practical example like this.

Next time I hope to build out the menu more, and maybe add some attractive css and play with other react hook features. My goal on this site is to simplify things like react into practical situations. I hope you enjoyed, and please check out the repo on my GitHub: Github/uzomezu and on twitter:@ios_Kevin. Thank you!

Discussion (8)

pic
Editor guide
Collapse
dance2die profile image
Sung M. Kim

Thanks for sharing Kevin~

Might you have a plan to add "animation" for hamburger menu dropdown?

Collapse
uzomezu profile image
Kevin Mezu Author

Yes! Definitely will write a post about that soon. Here's a good example of it in my E-commerce Store Project, take a look!

Collapse
dance2die profile image
Sung M. Kim

Much appreciated~

Thread Thread
uzomezu profile image
Kevin Mezu Author

A Man of my word, hope you enjoy! Hmaburger Animation

Thread Thread
dance2die profile image
Sung M. Kim

Wow. Thank you, Kevin for the post~!

Collapse
tundeiness profile image
Tunde Oretade

Hi Kevin, nice article I must say and it gives me ideas for a project I'm implementing. However, I have something I'm not too clear about in your implementation. You see, a react principle says "do not manipulate the DOM directly" and when I see this line of code in your implementation (const menuOverlay = document.querySelector(".overlay-menu"); ) It got me asking if this isn't against Reacts' principles? What do you think?

Collapse
uzomezu profile image
Kevin Mezu Author

Hey, that is certainly a point worth mentioning, Tunde! React works with the use of a virtual DOM or V-DOM. A virtual DOM window that syncs with the real DOM. Re-rendering and state change are the Go-To for react-apps as referencing the DOM can cause infinite re-renders, or i.e. not a good time.

Check out my article here on the usage of useRef() function, and how with certain react hooks, you can in fact reference the DOM, as long as you are not causing an additional re-render.