HeyImArt
HeyImArt

Reputation: 548

Next JS - Navbar onclick function undefined

I'm trying to make my navigation responsive, so clicking a burger menu icon will then add a class to the nav. Simple concept.

Still new to react and next js.

import Link from 'next/link'
import { useRouter } from 'next/router'
import { useRef, setState, useEffect } from 'react'

const Nav = (props) => {

  const router = useRouter()
  
  const isExpanded = () => {
    this.state = {
      isExpanded: false
    }
  }

  function handleToggle(e) {
    e.preventDefault();
    this.setState({
      isExpanded: !this.state.isExpanded
    });
  }

  return (
    <nav>
      <div>
        <Link href="/">
          <a><img src="/img/logo.svg" /></a>
        </Link>
        <button onClick={e => this.handleToggle(e)} className="nav-icon">
          <svg className="fill-current text-white" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/></svg>
        </button>
      </div>
      
      <div>
        <ul className={`collapsed ${isExpanded ? "is-expanded" : ""}`}>
          <li className={router.pathname == "/" ? "active" : ""}>
            <Link href="./">
              <a>Home</a>
            </Link>
          </li>
          <li className={router.pathname == "/blog" ? "active" : ""}>
            <Link href="/blog">
              <a>Blog</a>
            </Link>
          </li>
        </ul>
      </div>
    </nav>
    )
  }

export default Nav

When I click on the menu burger icon, I then get TypeError: Cannot read property 'handleToggle' of undefined

Any advice in the right direction would be greatly appreciated. Thank you

Upvotes: 1

Views: 1794

Answers (1)

pilchard
pilchard

Reputation: 12957

You are confusing class based and functional components and not leveraging the advantages of either. Here is a working snippet illustrating a minimal implementation.

It uses React.useState() to declare and set state. Also, when calling named functions event will be passed implicitly so you can simply declare onClick={handleToggle}.

p {
  font-family: monospace;
}
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
<div id="App"></div>
<script type="text/babel">
  const {useState} = React;
  
const Nav = () => {
  const [isExpanded, setIsExpanded] = useState(false);

  function handleToggle(e) {
    setIsExpanded(prevState => !prevState);
  }

  return (
    <nav>
      <div>
        <button type="button" onClick={handleToggle} className="nav-icon">
          Burger
        </button>
      </div>
      <p>{`isExpanded: ${isExpanded}`}</p>
    </nav>
    )
  }

ReactDOM.render(<Nav />, document.getElementById('App'));
 </script>

Upvotes: 2

Related Questions