繁体   English   中英

使用 react cloneElement 覆盖道具类型

[英]Using react cloneElement to over-ride prop type

我有这个TextField组件,它是接受字符串并使用 React.cloneElement 的输入表单,我正在尝试创建NumberField ,这是另一个输入表单,但采用数字类型。 当我使用 React.cloneElement 进行复制时,我想将TextField中的两个道具valueonChange从字符串更改为数字,但是我在来自NumberFielde.currentTarget.value上出现类型错误,说“类型的参数” string' 不可分配给“数字”类型的参数。” 我还在e.target.value上的 App.js 中收到另一个错误,说“类型‘数字’上不存在属性‘目标’。” 我要做的就是使用 cloneElement 来覆盖从字符串到数字的道具类型,但事实证明这很困难。 我究竟做错了什么? https://codesandbox.io/s/over-ride-prop-type-mjw1sp?file=/src/App.tsx

文本字段.tsx

import React from "react";
import "./styles.css";

export interface ITextField {
  onChange?: (value: string) => void;
  value?: string;
}

export const TextField: React.FC<ITextField> = ({ value = "", onChange }) => {
  const onChangeValue = (value: string) => {
    if (typeof onChange === "function") {
      onChange(value);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(e: React.FormEvent<HTMLInputElement>) =>
          onChangeValue(e.currentTarget.value)
        }
      />
    </div>
  );
};

数字字段.tsx

import React, { useState } from "react";
import "./styles.css";
import { TextField, ITextField } from "./TextField";

export interface INumberField extends Omit<ITextField, "onChange" | "value"> {
  onChange?: (value: number) => void;
  value: number;
  formatOnType?: boolean;
}

export const NumberField: React.FC<INumberField> = ({ value, onChange }) => {
  const [numberValue, setNumberValue] = useState<number>(0);
  const onChangeValue = (value: number) => {
    if (typeof onChange === "function") {
      onChange(value);
    }
  };

  return (
    <>
      {React.cloneElement(<TextField />, {
        value: numberValue,
        onChange: (e: React.FormEvent<HTMLInputElement>) =>
          onChangeValue(e.currentTarget.value)
      })}
    </>
  );
};

应用程序.tsx

import React, { useState } from "react";
import { NumberField } from "./NumberField";
import "./styles.css";

export default function App() {
  const [value, setValue] = useState(0);

  return (
    <div>
      <NumberField value={value} onChange={(e) => setValue(e.target.value)} />
    </div>
  );
}

在 HTML 输入(和反应输入)中,值是字符串。 React.FormEvent<HTMLInputElement>总是返回一个字符串。 现在我知道你想存储一个号码。 使用独立组件,这将提供以下内容:

export interface INumberField extends Omit<ITextField, "onChange" | "value"> {
  onChange?: (value: number) => void;
  value: number;
  formatOnType?: boolean;
}

export const NumberField = ({ value, onChange }: INumberField) => {
  // the input typed by the user is always a string
  const [value, setValue] = useState<string>('0');

  const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
      const numberValue = parseInt(e.target.value, 10);
      onChange(numberValue)
      setValue(e.target.value);
    }
  };

  return (
    <div>
      <input
        type="text"
        {/* automatically converted to string */}
        value={value}
        onChange={handleChange}
      />
    </div>
   );
};

至于重用 TextField 来构建 NumberField,恐怕你会与 TypeScript 战斗(并失败)。 正确的做法是编写一个通用输入,并按类型对其进行专门化。

export interface IField<T> {
  onChange: (value: T) => void;
  value: T;
  convert?: (value: string) => T;
}

export const Field = <T>({ value, onChange, convert = x => x }: IField<T>) => {{
  // the input typed by the user is always a string
  const [value, setValue] = useState<string>('0');

  const handleChange = (e: React.FormEvent<HTMLInputElement>) => {
      const parsedValue = convert(e.target.value);
      onChange(parsedValue)
      setNumberValue(e.target.value);
    }
  };

  return (
    <div>
      <input
        type="text"
        {/* automatically converted to string */}
        value={value}
        onChange={handleChange}
      />
    </div>
   );
};

那么你的领域是:

export interface ITextField extends IField<string> {}
const TextField = (props: ITextField) => <Field<string> {...props} /> 

export interface INumberField extends IField<number> {}
const NumberField = ({ value, onChange }: INumberField) => (
    <Field<number> value={value} onChange={onChange} convert={v => parseInt(v, 10)} /> 
);

暂无
暂无

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

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