如何包装一个内在组件,保留大部分 Props? [英] How do I wrap an intrinsic component, keeping most of the Props?

查看:26
本文介绍了如何包装一个内在组件,保留大部分 Props?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用我自己的 React 功能组件包装一个标准按钮,但我希望新组件的用户能够设置几乎所有底层按钮的道具.当然,我想保持正确的输入,所以如果 WrappedButton 包含一个 button,那么

I want to wrap a standard button with my own React functional component, but I want the user of the new component to be able to set almost all of the underlying button's props. Of course, I want to maintain the proper typing, so if WrappedButton encloses a button, then

<WrappedButton formNoValidate={true} onClick={handleClick} />

会正确编译但是

<WrappedButton formNoValidate={5} onKrapnik={handleClick} />

不会,因为 formNoValidate 被输入为布尔值并且 onKrapnik 不存在.

will not, both because formNoValidate is typed as a boolean and onKrapnik does not exist.

显然,我不想列出底层组件的合法道具的详尽(和脆弱)列表.

Obviously, I don't want to make an exhaustive (and fragile) list of the underlying component's legal props.

推荐答案

原始组件有一些 props.对于每个道具,你可能想要

The original component has some number of props. For each prop, you might want to

  • 原封不动地通过
  • 以某种方式修改
  • 省略
  • 改变它的类型

您可能还想添加一些自己的新道具.我们来看一个简单的案例,你只是想添加一些新的道具.我正在制作一种名为 MultiClick 的新型按钮,它添加了一个可选的道具:

You also might want to add some new props of your own. Let's take a simple case, you just want to add some new props. I'm making a new kind of button called MultiClick, which adds an optional prop:

type MultiClickProps = {
  clickCount?: number;
} & JSX.IntrinsicElements["button"];

const MultiClick: React.FC<MultiClickProps> = ({
  clickCount = 2,
  ...buttonProps
}) => {
// do some stuff
  return (
    <button {...buttonProps} />
  );
};

当然,这不是很有用:如果最终结果是返回一个按钮,所有的 props 都未经修改,那么一些东西"如何做任何有意义的事情?

Of course, that's not very useful: how would the "some stuff" do anything meaningful if the end result is to return a button with all the props passed through unmodified?

所以你可能想拦截和修改一些道具:

So you might want to intercept and modify some props:

const MultiClick: React.FC<MultiClickProps> = ({
  clickCount = 2,
  onClick,
  ...buttonProps
}) => {
  const handleClick = (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) => {
    // do some stuff
    onClick(event);
  };

  return (
    <button {...buttonProps} onClick={handleClick}/>
  );
};

这样,就有机会与包装组件的操作进行实际交互.

This way, there is an opportunity to actually interact with the actions of the wrapped component.

现在假设您不喜欢 onClick 的事件"参数并想替换其他东西,一个数字.要更改类型,您实际上必须省略旧道具并重新编写它,如下所示:

Now let's say you don't like the "event" argument to the onClick and want to substitute something else, a number. To change a type, you actually have to omit the old prop and re-write it, like so:

type MultiClickProps = {
  clickCount?: number;
  onClick: (n: number) => void;
} & Omit<JSX.IntrinsicElements["button"], 'onClick'>;

您可以在此处查看完成的代码.

You can see the finished code here.

顺便说一下,这一切都依赖于 JSX.IntrinsicElements 的存在,React 的人很友好地提供了它.假设您正在尝试从某个库中包装一个功能组件,而该组件没有导出一个整洁的 props 类型?

Incidentally, all this depends on the existence of JSX.IntrinsicElements, which the React people were kind enough to provide. Suppose you are trying to wrap a functional component from some library that did not export a neat props type?

幸运的是,您可以为任何用 Typescript 编写的功能组件生成自己的 props 类型,如下:

Fortunately, you can generate your own props type for any functional component written in Typescript, with this:

type PropsOf<T> =
    T extends React.FunctionComponent<infer U> ? U : never;

如果应用于上面的函数,就像这样:

which if applied to the function above, like so:

type MultiClickProps = PropsOf<typeof MultiClick>;

将评估为类似

type MultiClickProps = {
    clickCount?: number;
} & React.ClassAttributes<HTMLButtonElement> & React.ButtonHTMLAttributes<HTMLButtonElement>

这篇关于如何包装一个内在组件,保留大部分 Props?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆