我试图创建一个Rating
组件,它的边框带有一个模仿TextField
轮廓边框的标签。我找到了this,这个问题几乎涵盖了我想要做的事情,这意味着使用TextField
、inputComponent
和inputProps
来完成它。
import React, { useState } from "react";
import Stack from "@mui/material/Stack";
import Rating from "@mui/material/Rating";
import TextField from "@mui/material/TextField";
import { Favorite, FavoriteBorder } from "@mui/icons-material";
import "./styles.css";
const WrappedRating = React.forwardRef((props, ref) => {
const { className, onChange, value, ...rest } = props;
return (
<div className={className}>
<Rating
onChange={(e, value) => {
console.log("onChange", value);
onChange({ target: { value: String(value) } });
}}
value={Number(value)}
ref={ref}
{...rest}
/>
</div>
);
});
export default function App() {
const [value, setValue] = useState();
const onSubmit = (e) => {
e.preventDefault();
console.log(e);
};
return (
<Stack component="form" onSubmit={onSubmit}>
<TextField
value={value}
label="Rating"
onChange={(e) => {
console.log("onChange textField", e);
setValue(e.target.value);
}}
InputLabelProps={{
shrink: true
}}
InputProps={{
inputComponent: WrappedRating,
inputProps: {
max: 4,
onChangeActive: (e, newHover) => {
//console.log("hover", newHover);
},
icon: <Favorite fontSize="inherit" />,
emptyIcon: <FavoriteBorder fontSize="inherit" />
}
}}
/>
</Stack>
);
}
CodeSandBox link here
上面的代码可以工作,但我尝试使用TypeScript做同样的事情,而不使用any
或@ts-ginore
。
import React, { useState } from "react";
import Stack from "@mui/material/Stack";
import Rating, { RatingProps } from "@mui/material/Rating";
import TextField from "@mui/material/TextField";
import { Favorite, FavoriteBorder } from "@mui/icons-material";
import { InputBaseComponentProps } from "@mui/material";
type WrappedRatingProps = InputBaseComponentProps & RatingProps;
const WrappedRating = React.forwardRef<HTMLInputElement, WrappedRatingProps>(
(props, ref) => {
const { className, onChange, value, ...rest } = props;
return (
<div className={className}>
<Rating
onChange={(e, value) => {
const event: React.ChangeEvent<HTMLInputElement> = {
...e,
target: {
value: String(value)
}
// Type '{ value: string; }' is not assignable to type 'EventTarget & HTMLInputElement'.
};
if (onChange) {
onChange(event);
}
}}
value={Number(value)}
ref={ref}
{...rest}
/>
</div>
);
}
);
export default function App() {
const [value, setValue] = useState<number>(-1);
const [hover, setHover] = useState<number>(-1);
const onSubmit = (e: React.SyntheticEvent) => {
e.preventDefault();
console.log(e);
};
return (
<Stack component="form" onSubmit={onSubmit}>
<TextField
value={value}
label="Rating"
onChange={(e) => {
setValue(Number(e.target.value));
}}
InputLabelProps={{
shrink: true
}}
InputProps={{
inputComponent: WrappedRating,
inputProps: {
max: 4,
onChangeActive: (e: React.SyntheticEvent, newHover: number) => {
setHover(newHover);
console.log(hover);
},
icon: <Favorite fontSize="inherit" />,
emptyIcon: <FavoriteBorder fontSize="inherit" />
}
}}
/>
</Stack>
);
}
CodeSandBox link here
我已经注意到关于TextField和Rating的值有一个问题,这使得必须转换类型。现在的问题是让onChange
工作而不出现类型问题,因为TextField
和Rating
的onChange
期望不同的东西。我试图创建一个新的事件,但它开始变得非常混乱。
有什么想法吗?我知道any
或@ts-ginore
会让这个工作,但我想知道我是否错过了什么。这是我第一次问一个问题,我感谢任何反馈。
1条答案
按热度按时间js81xvg61#
我认为
onChange
中value
的类型已经是string
,因为它来自本用例中的输入事件,并且不应该需要通过创建新事件进行额外的转换。在分叉演示中测试:codesandbox,并且它似乎没有错误。
如果仍然存在关于类型不对齐的问题,是否可能有其他原因?