I am struggling with converting the following React.JS script to TypeScript. Can anyone help? I am trying to make a drop down nav bar in my website.
This is my Header.tsx file:
I am getting a red squiggly line on onClick={closeMobileMenu} - Property 'onClick' does not exist on type 'IntrinsicAttributes & { items: any; }'.
<ul className="navbar-nav">
{menuItems.map((menu, index) => {
return (
<MenuItems
items={menu}
key={index}
onClick={closeMobileMenu}
/>
);
})}
</ul>
This is my Menu.tsx file
I am getting an error on
- "items": Binding element 'items' implicitly has an 'any' type
- "contains":Property 'contains' does not exist on type 'never'
import React, { useState, useEffect, useRef } from "react";
import {HashLink} from "react-router-hash-link";
import Dropdown from "./Dropdown";
import "./Header.css";
interface MenuItems {
items: string
key: number
onClick: (param: any) => void
}
const MenuItems = ({ items }) => {
let ref = useRef();
const [dropdown, setDropdown] = useState(false);
const onm ouseEnter = () => {
window.innerWidth > 960 && setDropdown(true);
};
const onm ouseLeave = () => {
window.innerWidth > 960 && setDropdown(false);
};
useEffect(() => {
const handler = (event: { target: any; }) => {
if (dropdown && ref.current && !ref.current.contains(event.target)) {
setDropdown(false);
}
};
document.addEventListener("mousedown", handler);
document.addEventListener("touchstart", handler);
return () => {
// Cleanup the event listener
document.removeEventListener("mousedown", handler);
document.removeEventListener("touchstart", handler);
};
}, [dropdown]);
return (
<li
className="nav-item"
ref={ref}
onm ouseEnter={onMouseEnter}
onm ouseLeave={onMouseLeave}
onClick={() => setDropdown(false)}
>
{items.submenu ? (
<>
<button
type="button"
aria-haspopup="menu"
aria-expanded={dropdown ? "true" : "false"}
>
<HashLink smooth to={items.path} className="nav-link">
{items.title} <i className="fas fa-chevron-down"></i>
</HashLink>
</button>
<Dropdown submenus={items.submenu} dropdown={dropdown} />
</>
) : (
<HashLink
smooth to={items.path}
className="first-level-nav-link"
>
{items.title}
</HashLink>
)}
</li>
);
};
export default MenuItems;
This is my menuItems.tsx file:
export const menuItems = [
{
title: "Home",
path: "/",
cName: "nav-link",
submenu: [
{
title: "Story",
path: "/#story",
cName: "nav-link",
},
{
title: "Map",
path: "/#map",
cName: "nav-link",
}
],
},
{
title: "Rewards",
path: "/",
cName: "nav-link",
submenu: [
{
title: "competition",
path: "competition",
cName: "nav-link",
},
{
title: "prizes",
path: "prizes",
cName: "nav-link",
}
],
},
{
title: "Downloads",
path: "downloads",
cName: "nav-link",
}
];
CodePudding user response:
For error #2
TypeScript cannot actually infer how you intend to use this ref without any extra information.
const ref = useRef() // React.MutableRefObject<undefined>
However, useRef
can be used as a generic to tell TypeScript how you do intend on using the ref.
const ref = useRef<HTMLLIElement>(null) // React.MutableRefObject<HTMLLIElement>
Only then will TypeScript allow you to access ref.current.contains
, because it knows that the contains
property exists on a HTMLLIElement
node.
CodePudding user response:
Correction #1: For function reference as a parameter you need to define any data type
interface MenuItems {
items: any,
key: number,
onClick: any
}
Correction #2 : At your MenuItems Component.
const MenuItems = (props: MenuItems ) => {
//access menu item
console.log(props.items.title);
}