Milind
Milind

Reputation: 1955

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. while using React.js

I am getting an error:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

My Hook Code:

function WidthAndHeight() {
  const [width, setWidth] = React.useState(window.innerWidth);
  const [height, setHeight] = React.useState(window.innerHeight);

  React.useEffect(() => {
    window.addEventListener("resize", updateWidthAndHeight);
    return () => window.removeEventListener("resize", updateWidthAndHeight);
  });

  const updateWidthAndHeight = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
  };

  return (
    {
      "width": width,
      "height": height
    }
  );
}

When I call it on onMouseEnter it gives the error below:

class MegaMenu extends React.Component {
  public render() {
    return (
      <div className={styles.MegaMenu}>
        <div className={styles["menu-container"]}>
          <div className={styles.menu}>
            <MenuList Options={menus} />
          </div>
        </div>
      </div>
    )
  }
}

const MenuList = (props: IMenuListProps) => {
  const handleOnMouseEnter = () => {
    if (WidthAndHeight().width > 943) {
      console.log("WidthAndHeight().width")
    }
  }

  return (
    <ul onMouseEnter={handleOnMouseEnter}>
      {
        props.Options.map((Option: IMenu, index: number) => (
          <li key={index} className={(Option.subitem && Option.subitem.length > 0) ? styles["menu-dropdown-icon"] : styles["normal-sub"]} onMouseEnter={handleOnMouseEnter}>
            <a href={Option.link}>{Option.name}</a>
            {/* Base Case */}
            {
              (Option.subitem && Option.subitem.length > 0) &&
              <MenuList Options={Option.subitem} />
            }
          </li>
        ))
      }
    </ul>
  )
}

Can anyone guide me on how I can solve this issue?

Upvotes: 0

Views: 712

Answers (2)

Rafael Hovsepyan
Rafael Hovsepyan

Reputation: 781

You have already created custom hook, but used it wrong. The code below should work.

const MenuList = (props: IMenuListProps) => {
  const { width, height } = WidthAndHeight(); // --> call hook in component function body, not in eventhandler!
  const handleOnMouseEnter = () => {
    if (width > 943) {
      //...
    }
  }

  return (
    <ul onMouseEnter={handleOnMouseEnter}>
      {
        props.Options.map((Option: IMenu, index: number) => (
          <li key={index} className={(Option.subitem && Option.subitem.length > 0) ? styles["menu-dropdown-icon"] : styles["normal-sub"]} onMouseEnter={handleOnMouseEnter}>
            <a href={Option.link}>{Option.name}</a>
            {/* Base Case */}
            {
              (Option.subitem && Option.subitem.length > 0) &&
              <MenuList Options={Option.subitem} />
            }
          </li>
        ))
      }
    </ul>
  )
}

Upvotes: 2

Atin Singh
Atin Singh

Reputation: 3690

You need to use custom hook for what you are doing -

function useWidthAndHeight() {
  const [width, setWidth] = React.useState(window.innerWidth);
  const [height, setHeight] = React.useState(window.innerHeight);

  React.useEffect(() => {
    window.addEventListener("resize", updateWidthAndHeight);
    return () => window.removeEventListener("resize", updateWidthAndHeight);
  });

  const updateWidthAndHeight = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
  };

 const windowData =  {
      "width": width,
      "height": height
    }
  return (
   windowData
  );
}

export default function useWidthAndHeight

Then you can import it like this.

import useWidthAndWIndow from "./customHook.js"

And use it as a hook inside your functional component

const windowData = useWidthAndWIndow()

Upvotes: 0

Related Questions