Home > Enterprise >  typescript nav and Nextjs
typescript nav and Nextjs

Time:09-21

I'm learning typescript and I'm trying to build a navigation. I'm getting x Unexpected token header. Expected jsx identifier ,---- 25 |

I don't know what to make of this. Can someone advise as to where the issue might be?

Navbar.tsx file:

  import Link from "next/link";
import React, { useState } from "react";
import NavItem from "./NavItem";

export interface INavbar {
  navActive: boolean;
  
}


//export function Navbar(props: INavbar) {
const Navbar: React.FC<INavbar> = (className, ...navProps) => {

  const [navActive, setNavActive] = useState(null);
  const [activeIdx, setActiveIdx] = useState(-1);
  
const MENU_LIST :{ text: string, href: string}[] = [
    { text: "Home", href: "/" },
    { text: "About Us", href: "/about" },
    { text: "Contact", href: "/contact" },
  ];
 
  return (

    
    <header>
      <nav className={`nav`}>
        <Link href={"/"}>
          <a>
            <h1 className="logo">KT</h1>
          </a>
        </Link>

        <div
          onClick={() => setNavActive(!navActive)}
          className={`nav__menu-bar`}
        >
       
        </div>
        <div className={`${navActive ? "active" : ""} nav__menu-list`}>
          {MENU_LIST.map((menu, idx) => (
            <div
              onClick={() => {
                setActiveIdx(idx);
                setNavActive(false);
              }
              key={menu.text}
            >
              <NavItem active={activeIdx === idx} {...menu} />
            </div>
          )
        </div>
      </nav>
    </header>  
}

export default Navbar;

Navitem.tsx file:

import Link from 'next/link';

//Create a functional component with text, href and active as props and use Link from next/link to link pages
export interface INavItem {
  text: string;
  href: string;
  active: boolean;
}

const NavItem: React.FC<INavItem> = ({ text, href, active }) => {
  return (
    <Link href={href}>
      <a className={`nav__item ${active ? 'active' : ''}`}>{text}</a>
    </Link>
  );
};

export default NavItem;

CodePudding user response:

You seem to be missing some parenthesis/brackets. Your Navbar should look like this:

              }} <--- Added a bracket here
              key={menu.text}
            >
              <NavItem active={activeIdx === idx} {...menu} />
            </div>
          ))} <--- Added a parenthesis and a bracket
        </div>
      </nav>
    </header>  
)} <--- Added a parenthesis

One more issue is that the props passed to a component are passed as a single object, but in Navbar they are being used as if multiple objects were passed in.

Try changing:

const Navbar: React.FC<INavbar> = (className, ...navProps) => {

to:

const Navbar: React.FC<INavbar> = ({className, ...navProps}) => {

Now we are properly using the interface INavbar, but className is not expected in INavbar, so we need to either add className to INavbar or remove it from the props destructuring assignment. In this case, className is not being used anywhere, so we can remove it:

const Navbar: React.FC<INavbar> = ({...navProps}) => {

We are using navActive, but we are not using navProps anywhere, so we can further adjust what props are being destructured:

const Navbar: React.FC<INavbar> = ({ navActive }) => {

It looks like you are trying to use navActive as a props, and you are also defining it with useState... You can only do one or the other since navActive can't be both a state variable and a prop.

I'm guessing you want to pass it in as a prop, so the next instructions will be based on that assumption. In that case, we can go ahead and remove this line:

const [navActive, setNavActive] = useState(null);

Now we are getting the error Cannot find name 'setNavActive'. We'll need to define setNavActive, and since navActive is being passed in as a props, we'll have setNavActive also be passed in as a prop:

export interface INavbar {
  navActive: boolean;
  setNavActive: (value: boolean) => void;
}

const Navbar: React.FC<INavbar> = ({ navActive, setNavActive }) => {

Notice we set the type of setNavActive to be (value: boolean) => void in our INavBar. This means setNavActive is a function which expects one parameter of type boolean (called value).

Since we added setNavActive as an expected prop, Typescript now helps us out by telling us where <Navbar /> is used that Property 'setNavActive' is missing.

Wherever you are using Navbar, we now need to make sure we are passing in navActive and setNavActive as props like this:

<Navbar navActive={navActive} setNavActive={setNavActive} />

In that same component we also want to define navActive and setNavActive using useState. We will initialize navActive to false, since we defined navActive as a boolean:

const [navActive, setNavActive] = useState(false);

That is a lot of instructions, but I hope it was helpful. It may be useful to look at all of my suggestions applied at once, so I've created a full example on CodeSandbox where you can see everything working: Edit Navbar Debug

CodePudding user response:

It seems you didn't close the paranthesis in the return statement

return (
  <header>
   ...
  </header>
)
  • Related