【问题标题】:React with Typescript EventHandler type checking problem (onClick)React with Typescript EventHandler 类型检查问题 (onClick)
【发布时间】:2020-07-08 03:05:15
【问题描述】:

这些天我一直在用 Typescript 练习 React。

我的 PropsType 如下

export type PropType = {
  ingredientAdded: (type: keyof IngredientType) => void;
}

const buildControl: React.FunctionComponent<PropType> = (props) => (
  <div className={classes.BuildControl}>
    <div className={classes.Label}>{props.label}</div>
    <button className={classes.Less}>Less</button>
    <button className={classes.More} onClick={props.ingredientAdded as any}>More</button>
  </div>
);

作为身体。

这里的问题是我不能通过 onClick={props.ingredientAdded} 而不强制转换。

当我查看 onClick 类型时,它给了我

onClick?: MouseEventHandler<T>;
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;

似乎ingredientAdded: (type: keyof IngredientType) =&gt; void; 函数类型对onClick 无效。

不管怎样都行。

我的问题是在这里进行类型检查而不是强制转换为 any

的正确方法是什么

编辑

父组件传递函数。

type PropsType = {
  ingredientAdded(type: keyof IngredientType): void;
  ingredientRemoved(type: keyof IngredientType): void;
}

const controls: { label: string, type: keyof IngredientType }[] = [
  { label: 'Salad', type: 'salad' },
  { label: 'Bacon', type: 'bacon' },
  { label: 'Cheese', type: 'cheese' },
  { label: 'Meat', type: 'meat' },
];

const buildControls: React.FunctionComponent<PropsType> = (props) => (
  <div className={classes.BuildControls}>
    {controls.map(ctrl => (
      <BuildControl
        ingredientAdded={() => props.ingredientAdded(ctrl.type)}
        ingredientRemoved={() => props.ingredientRemoved(ctrl.type)}
        key={ctrl.label} label={ctrl.label} />
    ))}
  </div>
);

export default buildControls;

【问题讨论】:

  • 问题是,1)props.ingredientAdded 是否需要点击事件对象 2)它是如何得到它的type 参数的?
  • answer 1) 不需要点击事件处理程序。类型参数是从父组件传递的。我将编辑代码

标签: reactjs typescript


【解决方案1】:

请尝试将props.ingredientAdded 包装在一个函数中。

没有点击事件

const buildControl: React.FunctionComponent<PropType> = (props) => (
  <div className={classes.BuildControl}>
    <div className={classes.Label}>{props.label}</div>
    <button className={classes.Less}>Less</button>
    <button className={classes.More} onClick={() => { props.ingredientAdded() }}>More</button>
  </div>
);

有点击事件

const buildControl: React.FunctionComponent<PropType> = (props) => (
  <div className={classes.BuildControl}>
    <div className={classes.Label}>{props.label}</div>
    <button className={classes.Less}>Less</button>
    <button className={classes.More} onClick={(event: React.MouseEvent) => { props.ingredientAdded(event) }}>More</button>
  </div>
);

【讨论】:

  • props.ingredientAdded() 函数具有类型参数,该参数未包含在您的示例中,并且在子组件中也不可用。所以需要引用函数。
  • 我不认为以这种方式引用函数会在 React 和 TypeScript 中很好地发挥作用,但我不是专家。
  • 我的直觉是你可能需要重构你的代码以适应这个范例。
【解决方案2】:

这是因为 React 上的 onClick 期望您传递一个带有单个参数的函数,即鼠标事件。

你可以通过两种方式解决它:

  1. 用箭头函数包裹onClick
  // ...
  onClick={ (event) => { props.ingredientAdded(type) } }
  1. (最好的方法!) 在按钮的子组件上执行此逻辑,这样您的事件处理程序就不会明确知道 ingredientAdded 的依赖关系:

interface IngredientType {
  type: string;
}

export type PropType = {
  handler: (type: keyof IngredientType) => void;
  type: keyof IngredientType;
};

const MoreButton: React.FunctionComponent<PropType> = props => {
  const handleClick = () => {
    props.handler(props.type);
  };

  return <button onClick={handleClick}>More</button>;
};

const MainComponent = ({ingredientAdded, type}) => {
  return <MoreButton handler={ingredientAdded} type={type} />
}

Check the example for the second way.

【讨论】:

  • 对于第一种方法,可在此处找到类型。它是从父组件传递的。对于第二种方法,我知道还有其他方法可以做到这一点,但我不想改变组件的行为。我只是不明白为什么没有工作行为的类型定义
  • 我明白了。通常 TypeScript 和类型定义可以帮助我们检测可以改进代码的方法,这就是我提出第二种解决方案的原因。
猜你喜欢
  • 1970-01-01
  • 2019-04-22
  • 2021-01-03
  • 1970-01-01
  • 1970-01-01
  • 2020-03-09
  • 2021-11-01
  • 2021-11-14
  • 2023-01-09
相关资源
最近更新 更多