React+Mantine表单提交后无法清空输入框及弹窗实现求助
React + Mantine 报案表单:提交后清空失效与提示功能实现
问题说明
使用React结合Mantine组件开发报案表单,点击Submit按钮后数据已成功写入JSON文件,但输入框内容无法自动清空,尝试过修改handleSubmit、调用resetForm、DOM操作均无效;同时需要实现提交后的提示消息功能。
解决方案
1. 修复表单清空失效问题
核心原因是未将表单组件与state做双向绑定:React受控组件需要通过value属性将state值同步到组件,仅设置onChange无法让组件感知state变化。另外,Select组件的onChange建议使用函数式更新避免闭包问题。
修改点:
- 所有TextInput、Textarea添加
value属性,绑定对应formData字段 - Select组件的onChange改用函数式更新state,同时添加
value属性绑定对应字段
2. 实现提交提示消息功能
使用Mantine内置的Notifications组件实现弹窗提示,无需额外依赖:
- 导入
Notifications组件并在页面中渲染 - 在提交成功/失败时调用
showNotification方法显示对应提示
修改后的完整代码
import React, { useState } from 'react'; import { Select, Textarea, TextInput, Button, Notifications, showNotification } from '@mantine/core'; import classes from './Incident.module.css'; import axios from 'axios'; import moment from 'moment'; function Incident() { const [loading, setLoading] = useState(false); const initialFormData = { student_name: '', student_contact_no: '', student_email: '', datetime: '', category: '', additional_info: '', area: '' }; const [formData, setFormData] = useState({ ...initialFormData }); const handleInputChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value, })); }; const resetForm = () => { setFormData({ ...initialFormData }); }; const handleSubmit = async () => { try { setLoading(true); const form = new FormData() form.append("student_name", formData.student_name) form.append("student_contact_no", formData.student_contact_no) form.append("student_email", formData.student_email) form.append("datetime", moment(formData.datetime).format("YYYY-MM-DD hh:mm:ss")) form.append("category", formData.category) form.append("additional_info", formData.additional_info) form.append("area", formData.area) const response = await axios.put('/add_incident', form); if (response.status === 200) { showNotification({ title: "提交成功", message: "报案信息已成功提交", color: "green" }); resetForm(); } else { showNotification({ title: "提交失败", message: "报案信息提交出错,请重试", color: "red" }); console.error('Error creating incident'); } } catch (error) { showNotification({ title: "网络错误", message: "提交请求失败,请检查网络连接", color: "red" }); console.error('Network error', error); } finally { setLoading(false); } }; const inputContainerStyle = { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '30px', }; const marginMidStyle = { marginTop: '25px', }; return ( <div style={{ paddingTop: '20px' }}> <Notifications position="top-right" /> <div> <h2 style={{ textAlign: 'left' }}>Report a crime :</h2> </div> <div style={{ ...inputContainerStyle, ...marginMidStyle }}> <div style={{ flex: 1, marginRight: '10px' }}> <TextInput size="md" radius="md" variant="filled" label="Name" withAsterisk description="Full name as per NRIC" placeholder="Name" name="student_name" value={formData.student_name} onChange={handleInputChange} /> </div> <div style={{ flex: 1 }}> <TextInput size="md" radius="md" variant="filled" label="Contact Number" description="Enter your mobile number" placeholder="Contact Number" name="student_contact_no" value={formData.student_contact_no} onChange={handleInputChange} /> </div> </div> <div style={{ ...inputContainerStyle, ...marginMidStyle }}> <div style={{ flex: 1, marginRight: '10px' }}> <TextInput size="md" radius="md" variant="filled" label="Email Address" description="Enter your email address" placeholder="Email" name="student_email" value={formData.student_email} onChange={handleInputChange} /> </div> <div style={{ flex: 1 }}> <TextInput size="md" radius="md" variant="filled" label="Date" description="Enter the date of report" placeholder="DD/MM/YYYY" name="datetime" value={formData.datetime} onChange={handleInputChange} /> </div> </div> <div style={{ ...inputContainerStyle, ...marginMidStyle }}> <div style={{ flex: 1, marginRight: '10px'}}> <Select classNames={{ option: classes.wrapper }} size="md" radius="md" variant="filled" label="Crime Category" description="Description" placeholder="Select" data={['Theft', 'Vandalism', 'Peeping Tom', 'Assault']} name="category" value={formData.category} onChange={(e) => { setFormData(prev => ({...prev, category: e})) }} /> </div> <div style={{ flex: 1}}> <Select classNames={{ option: classes.wrapper }} size="md" radius="md" variant="filled" label="General location of Crime" description="Pick where the crime occured" placeholder="Select" data={['Level 1', 'Level 2']} name="area" value={formData.area} onChange={(e) => { setFormData(prev => ({...prev, area: e})) }} /> </div> </div> <div style={{...marginMidStyle}}> <Textarea size="md" radius="md" label="Detail of crime" variant="filled" description="Include the relevant details, including to specify the exact location of crime" placeholder="Details of crime here (Eg. Description of peeeping tom occuring at 3rd floor toilet)" name="additional_info" value={formData.additional_info} onChange={handleInputChange} autosize minRows={5} maxRows={10} /> </div> <Button variant="filled" onClick={handleSubmit} loading={loading} style={{ position: "absolute", bottom: "50px", right: "20px", }} > Submit </Button> </div> ); } export default Incident;
额外说明
- 移除了原代码中未使用的
success状态,改用通知组件直接反馈结果 - 给Button添加了
loading={loading}属性,提交时显示加载状态,提升用户体验 - 所有state更新改用函数式写法,避免闭包导致的state不同步问题
内容的提问来源于stack exchange,提问作者Tiff
相关产品推荐
相关产品推荐

