![](/img/trans.png)
[英]How to over-ride onChange prop from another component using cloneElement?
[英]Using react cloneElement to over-ride prop type
我有这个TextField
组件,它是接受字符串并使用 React.cloneElement 的输入表单,我正在尝试创建NumberField
,这是另一个输入表单,但采用数字类型。 当我使用 React.cloneElement 进行复制时,我想将TextField
中的两个道具value
和onChange
从字符串更改为数字,但是我在来自NumberField
的e.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.