React+Typescript+Material-UI表单验证及提交时接口调用实现咨询
实现方案
接口调整
你现有postTicket接口没有接收提交的表单数据,需要先修改成支持传参:
export interface TicketDTO { title?: string; } // 新增data参数,接收要提交的工单数据 export async function postTicket(data: TicketDTO): Promise<AxiosResponse<TicketDTO[]>> { return await axios.post<TicketDTO[]>( `${baseUrl}/support/tickets/create`, data // 把表单数据放到请求体里 ); }
组件完整实现
我们通过React内置useState维护表单状态、校验错误、加载状态,结合MUI TextField的自带错误提示能力实现校验,提交时触发接口请求:
import { useState } from 'react'; import { Container, Box, TextField, Button, CircularProgress, Alert } from '@mui/material'; // 导入你的接口和类型 import { postTicket, TicketDTO } from '你的接口文件路径'; export default function OpenTicket(props: any) { const classes = useStyles(); // 表单状态 const [formData, setFormData] = useState<TicketDTO>({ title: '' }); // 校验错误状态 const [errors, setErrors] = useState<{title?: string}>({}); // 提交加载状态 const [loading, setLoading] = useState(false); // 提交结果提示 const [submitMsg, setSubmitMsg] = useState<{type: 'success'|'error', content: string}|null>(null); // 输入框内容变化同步 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); // 输入时清除对应字段的错误提示 if (errors[name as keyof typeof errors]) { setErrors(prev => ({ ...prev, [name]: undefined })); } }; // 表单校验逻辑 const validateForm = () => { const newErrors: {title?: string} = {}; // 这里可以自定义校验规则,比如title必填,最小长度等 if (!formData.title?.trim()) { newErrors.title = '工单标题不能为空'; } else if (formData.title.trim().length < 5) { newErrors.title = '标题长度不能少于5个字符'; } setErrors(newErrors); // 没有错误则校验通过 return Object.keys(newErrors).length === 0; }; const formHandler = async (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); setSubmitMsg(null); // 先校验表单 const isValidatePass = validateForm(); if (!isValidatePass) return; // 校验通过提交接口 try { setLoading(true); await postTicket(formData); setSubmitMsg({ type: 'success', content: '工单提交成功' }); // 提交成功清空表单 setFormData({ title: '' }); } catch (err) { setSubmitMsg({ type: 'error', content: '工单提交失败,请稍后重试' }); console.error('提交错误:', err); } finally { setLoading(false); } }; return ( <Container> <Box m={5}> <div className={classes.root}> <form onSubmit={formHandler}> {/* 提交结果提示 */} {submitMsg && <Alert severity={submitMsg.type} sx={{ mb: 2 }}>{submitMsg.content}</Alert>} <TextField id="outlined-full-width" label="Name" name="title" // 要和formData里的字段名对应 value={formData.title || ''} onChange={handleInputChange} error={!!errors.title} // 控制错误状态 helperText={errors.title} // 错误提示内容 fullWidth margin="normal" /> <Button type="submit" // 一定要加type="submit"才能触发form的onSubmit事件 variant="contained" disabled={loading} // 加载时禁用按钮 > {loading ? <CircularProgress size={20} color="inherit" /> : 'Submit'} </Button> </form> </div> </Box> </Container> ); }
关键说明
- 给提交按钮加上
type="submit"属性,点击时才会自动触发form的onSubmit事件 - 如果有更复杂的多字段校验、联动校验需求,推荐搭配
react-hook-form+zod实现,代码会更简洁,TS类型适配也更友好 - 加载状态下禁用按钮可以避免重复提交的问题
内容的提问来源于stack exchange,提问作者Peter Penzov
相关产品推荐
相关产品推荐

