如何解决React TypeScript、HooksForm、是的和 MaterialUI 自动完成
我在 React Hook From 中使用 Yup 进行 MUI 自动完成验证时遇到问题。当我 concole.log
我的对象 (GrandLodge) 时,countryID
和 unionID
的道具总是 "0"
。
这是我的组件。
- 首先是我控制的自动完成:
import { TextField,Typography } from "@material-ui/core";
import { Autocomplete } from "@material-ui/lab";
import React,{ ChangeEvent } from "react";
import { Control,Controller,DeepMap,FieldError } from "react-hook-form";
import { Country,Union } from "./../../../service/client";
import { IBaseProps } from "./../Interfaces/BaseProps";
Country,GrandLodge,Lodge,Union,} from "./../../../service/client";
import { IBaseProps } from "./../Interfaces/BaseProps";
interface IHookFormSelectlistProps<T> extends IBaseProps {
name: string;
control: Control;
errors?: DeepMap<Record<string,any>,FieldError>;
disabled?: boolean;
data: Array<T>;
displayMember: (item: T) => string;
valueMember: (item: T) => string;
style?: React.Cssproperties;
selectedValue?: any;
onChange?: (item: T) => void;
label?: string;
className?: string;
value: T | null;
}
interface IHookFormSelectlistState {
setopen: boolean;
}
type CustomSelect<T> = new (
props: IHookFormSelectlistProps<T>
) => HookFormSelectList<T>;
class HookFormSelectList<T> extends React.Component<
IHookFormSelectlistProps<T>,IHookFormSelectlistState
> {
constructor(props: IHookFormSelectlistProps<T>) {
super(props);
this.state = {
setopen: false,};
}
private onInputChange = (
e: ChangeEvent<{}>,value: string | T | null
): void => {
if (this.props.onChange) {
const item: T = this.props.data.toEnum().First((x: T) => x === value);
this.props.onChange(item);
}
};
render() {
const body = () => (
<React.Fragment>
<Controller
render={({ value,onBlur,onChange }) => (
<div className={this.props.className}>
<Autocomplete
freeSolo
fullWidth
openOnFocus={true}
onChange={(e: ChangeEvent<{}>,v: string | T | null) => {
onChange(e);
this.onInputChange(e,v);
}}
onopen={() => this.setState({ ...this.state,setopen: true })}
onClose={() => this.setState({ ...this.state,setopen: false })}
getoptionSelected={(option,selected) => option === selected}
getoptionLabel={this.props.displayMember}
options={this.props.data}
loading={false}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder={this.props.label}
/>
)}
/>
</div>
)}
defaultValue={this.props.value}
name={this.props.name}
control={this.props.control}
onChangeName="onChange"
/>
{this.props.errors && this.props.errors[this.props.name] && (
<Typography variant="caption" color="error">
<small>
<span role="alert" id={`${this.props.name}Error`}>
{this.props.errors[this.props.name].message}
</span>
</small>
</Typography>
)}
</React.Fragment>
);
return body();
}
}
export const CountriesSelect: CustomSelect<Country> = HookFormSelectList;
export const UnionSelect: CustomSelect<Union> = HookFormSelectList;
- 我是的验证架构:
import * as Yup from "yup";
export const validationSchema = Yup.object().shape({
name: Yup.string()
.required("This field is required.")
.min(2,"Lodge name has to be at last 2 charachters long.")
.max(255,"Name can't be longer then 255 charachters."),countryId: Yup.string()
.required("This field is required.")
.min(0,"Country has to be selected."),email: Yup.string()
.required("This field is required.")
.email("Not a valid e-mail adress."),unionId: Yup.string()
.required("This field is required.")
.min(0,"Union has to be selected."),pypalAccount: Yup.string()
.required("This field is required.")
.min(2,"Pypal account has to be at last 2 charachters long.")
.max(255,"Pypal account can't be longer then 255 charachters."),cryptoWallet: Yup.string()
.required("This field is required.")
.min(2,"Crypto wallet has to be at last 2 charachters long.")
.max(255,"Crypto wallet can't be longer then 255 charachters."),});
- 我的 GrandLodge 对象:
export interface GrandLodge {
time: Date;
timeStamp: Date;
readonly grandLodgeId: number;
unionId: number;
countryId: number;
name: string | undefined;
email: string | undefined;
pypalAccount: string | undefined;
cryptoWallet: string | undefined;
}
- 还有我的组件:
import { yupResolver } from "@hookform/resolvers/yup";
import {
Button,Container,CssBaseline,Grid,Typography,} from "@material-ui/core";
import React,{ useEffect,useState } from "react";
import { useForm } from "react-hook-form";
import HookFormTextBox from "./../../../library/HookForm/Components/hookFomTextBox";
import { useStyles } from "./../../style.main";
import { validationSchema } from "./validationSchema";
import { Country,Union } from "./../../../service/client";
import {
CountriesSelect,UnionSelect,} from "./../../../library/HookForm/Components/hookFormSelectlist";
import { withConnected } from "../../../state/withConnected";
import { WebAPI } from "./../../../service/webAPI";
interface IProps {
countries: Country[];
}
const GrandLodgePageBase = (props: IProps): JSX.Element => {
const [serverError,setServerError] = useState<string>("");
const [unions,setUnions] = useState<Union[]>([]);
useEffect(() => {
const fetchData = async (): Promise<void> => {
setUnions(await WebAPI.Union.getPage(0,1000));
};
fetchData();
},[]);
const classes = useStyles();
const { control,handleSubmit,errors,formState } = useForm<GrandLodge>({
mode: "onChange",resolver: yupResolver(validationSchema),});
const onSubmit = async (data: GrandLodge): Promise<void> => {
if (!formState.isValid) {
return;
}
console.log(data);
};
return (
<Container component="main" maxWidth="xl">
<CssBaseline />
<Typography className={classes.title} variant="overline">
Add new grand lodge
</Typography>
<form
className={classes.form}
onSubmit={handleSubmit((data: GrandLodge) => onSubmit(data))}
>
<Grid container className={classes.root} spacing={2}>
<Grid item xs={12} sm={12} md={12} lg={6}>
<HookFormTextBox
name="name"
type="text"
label="Lodge Name"
control={control}
errors={errors}
className={classes.formElement}
/>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={6}>
<HookFormTextBox
name="email"
type="email"
label="E-mail"
control={control}
errors={errors}
className={classes.formElement}
/>
</Grid>
</Grid>
<Grid container className={classes.root} spacing={2}>
<Grid item xs={12} sm={12} md={12} lg={6}>
<CountriesSelect
name="countryId"
label="Country"
displayMember={(x) => x.name!}
valueMember={(x) => x.countryId.toString()}
value={null}
data={props.countries}
control={control}
errors={errors}
className={classes.formElement}
/>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={6}>
<UnionSelect
name="unionId"
label="Union"
displayMember={(x) => x.name!}
valueMember={(x) => x.unionId.toString()}
data={unions}
value={null}
control={control}
errors={errors}
className={classes.formElement}
/>
</Grid>
</Grid>
<Grid container className={classes.root} spacing={2}>
<Grid item xs={12} sm={12} md={12} lg={6}>
<HookFormTextBox
name="cryptoWallet"
type="text"
label="Crypto Wallet"
control={control}
errors={errors}
className={classes.formElement}
/>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={6}>
<HookFormTextBox
name="pypalAccount"
type="text"
label="Pypal Account"
control={control}
errors={errors}
className={classes.formElement}
/>
</Grid>
</Grid>
<Grid item xs={12} sm={12} md={12} lg={12} justify="center" container>
<Button
type="submit"
variant="contained"
color="primary"
className={classes.submit}
disabled={!formState.isValid}
>
SAVE
</Button>
</Grid>
<Grid item md>
<Typography variant="subtitle2" color="error" align="center">
{serverError}
</Typography>
</Grid>
</form>
</Container>
);
};
const GrandLodgePage = withConnected(GrandLodgePageBase,(s) => ({
countries: s.state.countries,}));
export default GrandLodgePage;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。