Home > other >  In React.js w/Typescript, how do you create a onClick function that also passes another parameter?
In React.js w/Typescript, how do you create a onClick function that also passes another parameter?

Time:02-23

New to react & typescript so if there's a better way to do this, please let me know. I want to combine these 2 functions in a React component to be 1:

// Opens the overlay menu
function openOverlayHandler() {
 setOverlayIsOpen(true);
}

// Closes the overlay menu
function closeOverlayHandler() {
 setOverlayIsOpen(false);
}

Instead something like this:

function toggleOverlayHandler(isOpen: boolean): void {
  setOverlayIsOpen(isOpen)
} 

It would be fired using the onClick attribute. Examples:

<Image
  src={iconMenu}
  alt="Open Menu"
  className={styles["header__overlay-icon"]}
  onClick={toggleOverlayHandler(true)}
/>

In case it helps, here's the complete component:

// Import React modules
import { useState } from "react";

// Import Next modules
import Image from "next/image";
import Link from "next/link";

// Import Next Drupal modules
import { getMenu } from "next-drupal";

// Import component dependencies
import OverlayMenu from "../../molecules/OverlayMenu";

// Import media
import logo from "../../../public/svgs/logo.svg";
import iconMenu from "../../../public/svgs/icon-menu.svg";
import iconEmail from "../../../public/svgs/icon-email.svg";
import iconPhone from "../../../public/svgs/icon-phone.svg";

// Import component module styles
import styles from "./header.module.scss";

// Create the component
const Header: React.FC<{ menu: any }> = ({ menu }) => {
  // Define the component states
  const [overlayIsOpen, setOverlayIsOpen] = useState(false);

  // @TODO - Can we collapse the 2 functions below to one, something like toggleOverlayHandler(isOpen: boolean)

  // Opens the overlay menu
  function openOverlayHandler() {
    setOverlayIsOpen(true);
  }

  // Closes the overlay menu
  function closeOverlayHandler() {
    setOverlayIsOpen(false);
  }

  return (
    <header className={styles.header}>
      <Link href="/">
        <a className={styles["header__logo-link"]}>
          <Image
            src={logo}
            alt={process.env.SITE_NAME}
            className={styles.header__logo}
          />
        </a>
      </Link>

      <ul className={styles["header__contact-list"]}>
        <li>
          <a href={`tel:${process.env.PRIMARY_PHONE}`}>
            <Image src={iconPhone} alt="Call Us" />
          </a>
        </li>
        <li>
          <a href={`mailto:${process.env.PRIMARY_EMAIL}`}>
            <Image src={iconEmail} alt="Email Us" />
          </a>
        </li>
      </ul>

      <nav>
        <ul>
          {menu?.map((item: any) => {
            return (
              <li key={item.id}>
                <Link href={item.url} passHref>
                  <a>{item.title}</a>
                </Link>
              </li>
            );
          })}
        </ul>
      </nav>

      <Image
        src={iconMenu}
        alt="Open Menu"
        className={styles["header__overlay-icon"]}
        onClick={openOverlayHandler}
      />

      {overlayIsOpen && <OverlayMenu onCloseClick={closeOverlayHandler} />}
    </header>
  );
};

// Define the props at build
export async function getStaticProps() {
  const { tree } = await getMenu("main");

  return {
    props: {
      menu: tree,
    },
  };
}

// Export the component
export default Header;

CodePudding user response:

Instead something like this:

function toggleOverlayHandler(isOpen: boolean): void {
 setOverlayIsOpen(isOpen)
} 

The above code is fine, but you're using it wrong. When you do this:

onClick={toggleOverlayHandler(true)}

...that means "immediately call toggleOverlayHandler(true), and pass its return value into onClick". So you end up running the code during rendering, not when the click happens. Instead, you need to pass a function to onClick, as in:

onClick={() => toggleOverlayHandler(true)}
  • Related