1

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

2
  • You are using functional component. It doesn't exist of this. Just use handleToggle(e) would be fine. Commented Aug 25, 2020 at 9:33
  • Ah okay thank you - so I have made that change - now I get cannot read property 'setState' of undefined Commented Aug 25, 2020 at 9:41

1 Answer 1

2

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>

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.