Creating a Custom Button in React Typescript and add onClick Event
Asked Answered
O

4

10

I am trying to create a custom button component in a React Typescript project that use React Hooks and Styled components.

// Button.tsx
import React, { MouseEvent } from "react";
import styled from "styled-components";

export interface IButtonProps {
    children?: React.ReactNode;
    props?: any;
    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
        | undefined;
}

const Button: React.FC<IButtonProps> = ({
    children,
    onClick = () => {},
    ...props
}) => {
    const handleOnClick = (e: MouseEvent<HTMLButtonElement>) => {
        onClick(e);
    };
    return (
        <ButtonStyles onClick={handleOnClick} {...props}>
            {children}
        </ButtonStyles>
    );
};

export default Button;

const ButtonStyles = styled.button``;

This is the component I want to use my custom Button

// Login.tsx
import React from "react";
import Button from "../../components/Generic/Button/Button";

const Login: React.FC = () => {
    const clickMe = () => {
        console.log("Button Clicks");
    };

    return (
        <div>
            <Button onClick={clickMe}>My Button</Button>
        </div>
    );
};

export default Login;

I want to click on my custom button and want to print the console log message when I click on it. But I am getting the following error. How to resolve this issue?

Argument of type 'MouseEvent<HTMLButtonElement, MouseEvent>' is not assignable to parameter of type 'MouseEvent<HTMLButtonElement, MouseEvent<Element, MouseEvent>>'.
  Type 'MouseEvent' is missing the following properties from type 'MouseEvent<Element, MouseEvent>': nativeEvent, isDefaultPrevented, isPropagationStopped, persist  TS2345

    16 | }) => {
    17 |    const handleOnClick = (e: MouseEvent<HTMLButtonElement>) => {
  > 18 |        onClick(e);
       |                ^
    19 |    };
    20 |    return (
    21 |        <ButtonStyles onClick={handleOnClick} {...props}>
Odisodium answered 27/2, 2020 at 15:7 Comment(4)
I believe your clickMe method is missing the event argument. Try chaning it to clickMe(e).Niobous
@Niobous I think you mean this: <Button onClick={e => clickMe(e)}>My Button</Button> , but still getting the error.Odisodium
No, I mean where you actually create clickMe, so const clickMe = () => {...} should be const clickMe = (e) => {...}Niobous
nope, it didn't work as well.Odisodium
L
6

Your interface IButtonProps defines the expected signature of onClick

    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
        | undefined;

However, the e argument to handleClick is defined differently as MouseEvent<HTMLButtonElement>

If you change the onClick signature to match your handleClick definition, that may go some way to fix it?

    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement>) => void)
        | undefined;
Lashawn answered 27/2, 2020 at 15:54 Comment(0)
U
19

UPDATED:

if you want to include them aria props enter image description here

new


import React from "react";

export interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, React.AriaAttributes  {}

export const ButtonPrimary:React.FC<ButtonProps> = props => {
    const {children, ...rest} = props;

    return (
        <button {...rest}>{children}</button>
    )
}

old

import * as React from "react";


export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}


/**
 * Button.
 *
 * @param {ButtonProps} props button's props
 * @returns {React.ReactElement<ButtonProps>} Button.
 */
export function Button(props: ButtonProps): React.ReactElement<ButtonProps> {
    const { children, ...rest } = props;
    return (
        <button
            {...rest}
        >
            {children}
        </button>
    );
}
Unthinkable answered 28/2, 2020 at 8:42 Comment(1)
The useful part for me was interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {Rhizopod
L
6

Your interface IButtonProps defines the expected signature of onClick

    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void)
        | undefined;

However, the e argument to handleClick is defined differently as MouseEvent<HTMLButtonElement>

If you change the onClick signature to match your handleClick definition, that may go some way to fix it?

    onClick?:
        | ((event: React.MouseEvent<HTMLButtonElement>) => void)
        | undefined;
Lashawn answered 27/2, 2020 at 15:54 Comment(0)
O
3
// Button.tsx
import React from "react";
import styled from "styled-components";

interface IButtonProps {
    children?: React.ReactNode;
    props?: any;
    onClick?: any;
}

const MyButton: React.FC<IButtonProps> = ({ onClick, children, ...props }) => {
    return (
        <ButtonStyles {...props} onClick={onClick}>
            {children}
        </ButtonStyles>
    );
};

export default MyButton;

const ButtonStyles = styled.button``;

// Login.tsx
import React from "react";
import MyButton from "../../components/Generic/Button/Button";

const Login: React.FC = () => {
    const ClickMe = () => {
        console.log("Button Clicked");
    };

    return (
        <div>
            <MyButton onClick={ClickMe}>Hello MY Button</MyButton>
        </div>
    );
};

export default Login;

I just able to fix the issue by changing the type of onClick?: any This is not the best solution, but at least it didn't throw any error and I can perform the onClick action in my Login.tsx.

Odisodium answered 28/2, 2020 at 3:28 Comment(0)
R
0

The code snippet should work fine.

export interface ButtonProps
    extends React.ButtonHTMLAttributes<HTMLButtonElement> {
    // customProps
  }

const Button: React.FC<ButtonProps> = ({ children }) => {
    return <button>{children}</button>;
};

export default Button;
Rhombohedron answered 20/10, 2023 at 14:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.