You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 20:04:51