繁体   English   中英

React Typescript 触发 onClick 按钮事件 using.bind

[英]React Typescript fire onClick button event using .bind

我有以下Cart.tsx代码,其中包含两个函数onRemoveonAdd以及.bind()传递一些数据:

const Cart = (props: CartProps) => {
  // ...

  const cartItemRemoveHandler = (id: string) => {    
    console.log("CartItemRemoveHandler");
  };

  const cartItemAddHandler = (item: CartItemProps) => {
    console.log("CartItemAddHandler");
  };

  const cartItems = (
    <ul className={classes["cart-items"]}>
      {cartCtx.items.map((item) => (
        <CartItem
          key={item.id}
          id={item.id}
          name={item.name}
          amount={item.amount}
          price={item.price}
          onRemove={cartItemRemoveHandler.bind(null, item.id)}
          onAdd={cartItemAddHandler.bind(null, item)}
        />
      ))}
    </ul>
  );
  
  // ...
};

CartItem.tsx

export interface CartItemProps {
  id: string;
  name: string;
  amount: number;
  price: number;
  onAdd?: (id: string) => void;
  onRemove?: (item: CartItemProps) => void;
}

const CartItem = (props: CartItemProps) => {
  const price = `$${props.price.toFixed(2)}`;

  return (
    <li className={classes["cart-item"]}>
      <div>
        <h2>{props.name}</h2>
        <div className={classes.summary}>
          <span className={classes.price}>{price}</span>
          <span className={classes.amount}>x {props.amount}</span>
        </div>
      </div>
      <div className={classes.actions}>
        <button onClick={props.onRemove}>-</button>
        <button onClick={props.onAdd}>+</button>
      </div>
    </li>
  );
};

错误发生在按钮中onClick函数的 CartItem.tsx 处。 onClick红色下划线,错误如下:

(JSX attribute) React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined

Type '((id: string) => void) | undefined' is not assignable to type 'MouseEventHandler<HTMLButtonElement> | undefined'.
  Type '((id: string) => void' is not assignable to type 'MouseEventHandler<HTMLButtonElement>'.
    Types of parameters 'id' and 'event' are incompatible.
      Type 'MouseEvent<HTMLButtonElement, MouseEvent>' is not assignable to type 'string'
The expected type comes from property 'onClick' which is declared here on type 'DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>'

我不需要事件属性。 我只想在单击按钮时执行 function 。 我可以解决这个问题吗? 帮助表示赞赏。

更新:通过将接口onAddonRemove声明更改为: onAdd?: () => void;解决了错误onRemove?: () => void; . 本质上,我只是从界面中的函数中删除了参数,结果如下:

export interface CartItemProps {
  id: string;
  name: string;
  amount: number;
  price: number;
  onAdd?: () => void;
  onRemove?: () => void;
}

.bind()函数正在处理 arguments。 也不需要在界面中定义它们,这是我的错误。

在 onClick 中使用箭头 function:

export interface CartItemProps {
    id: string;
    name: string;
    amount: number;
    price: number;
    onAdd?: (id: string) => void;
    onRemove?: (item: CartItemProps) => void;
  }
  
  const CartItem = (props: CartItemProps) => {
    const price = `$${props.price.toFixed(2)}`;
  
    const item = { 
        id: props.id,
        name: props.name,
        amount: props.amount,
        price: props.price,
    } as CartItemProps;
    return (
      <li className={classes["cart-item"]}>
        <div>
          <h2>{props.name}</h2>
          <div className={classes.summary}>
            <span className={classes.price}>{price}</span>
            <span className={classes.amount}>x {props.amount}</span>
          </div>
        </div>
        <div className={classes.actions}>
          <button onClick={() => props.onRemove?.(item)}>-</button>
          <button onClick={() => props.onAdd?.(item.id)}>+</button>
        </div>
      </li>
    );
  };

专注于错误链的这一行:

Type '((id: string) => void) | undefined' is not assignable to type 'MouseEventHandler<HTMLButtonElement> | undefined'.

此错误表明您配置为onAdd挂钩的类型与接受MouseEvent<...> object 作为第一个参数的onClick处理程序不兼容。

但是,因为您将iditem绑定在Cart元素内,所以实际上是将类型为() => void的函数传递给CartItem ,这与您的接口声明不同。 这些() => void函数与onClick处理程序兼容,因为它们忽略传递给它们的任何 arguments。

因此,您可以通过将界面更新为:

export interface CartItemProps {
  id: string;
  name: string;
  amount: number;
  price: number;
  onAdd?: () => void;
  onRemove?: () => void;
}

这使您可以继续按原样使用以下部分:

// Cart
onRemove={cartItemRemoveHandler.bind(null, item.id)}
onAdd={cartItemAddHandler.bind(null, item)}
// CartItem
<button onClick={props.onRemove}>-</button>
<button onClick={props.onAdd}>+</button>

However, if in the future cartItemAddHandler or cartItemRemoveHandler have more parameters added to them, and you don't bind all of the arguments of the function handlers properly, you will start getting MouseEvent<...> objects passed through to your function unexpectedly.

// Cart
cartItemRemoveHandler = (id: string, quantity: number) => { ... }
/* ... */
onRemove={cartItemRemoveHandler.bind(null, item)}
// CartItem
export interface CartItemProps
  /* ... */
  onRemove?: () => void;
  /* ... */
}
/* ... */
<button onClick={props.onRemove}>-</button>

在运行时,当onAdd被触发时,这里的quantity将被赋予MouseEvent<...> ,而不是number

您可以通过更新接口以接受MouseEventHandler<HTMLButtonElement>对象来防止此类错误,以便 TypeScript 在您未正确绑定处理程序时适当地报告错误。

export interface CartItemProps {
  id: string;
  name: string;
  amount: number;
  price: number;
  onAdd?: MouseEventHandler<HTMLButtonElement>;
  onRemove?: MouseEventHandler<HTMLButtonElement>;
}

此外,您可以交换以下行以防止将 MouseEvent 传递到错误的位置:

cartItemRemoveHandler.bind(null, item)

为了:

() => cartItemRemoveHandler(item)
// or
(ev: MouseEvent<...>) => cartItemRemoveHandler(item) // no need to explicitly type the `ev` as a MouseEvent here, it will be inferred from the interface.

旁注:即使进行了这些更改,您用于onAdd的处理程序也接受项目 object,但onRemove接收字符串。 与您的原始界面相比,这是向后的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM