React模态框表单提交后UI无法稳定更新的问题求助
问题分析与解决思路
核心问题
提交表单后UI更新不稳定,根源是createRequest是异步操作,当前代码中直接调用fetchData,可能在新数据还未写入数据库时就执行查询,导致读取的仍是旧数据。同时fetchData的异步逻辑处理不规范,也可能加剧时序问题。直接用setSearchedMain(prev => [...prev, newRequest])虽然更新稳定,但缺失数据库生成的自增ID,无法满足后续操作需求。
解决步骤
- 等待创建请求完成后再刷新数据:将
handleSave改为异步函数,确保createRequest执行完成(数据写入数据库)后,再调用fetchData拉取最新列表。 - 规范异步逻辑处理:在
fetchData中使用await处理Promise,替代嵌套的then,让代码逻辑更清晰,避免时序混乱。 - 优化列表key值:后续拿到数据库返回的自增ID后,将列表项的key从
index替换为ID,避免列表更新时的渲染异常。 - 重置表单状态:提交成功后清空表单状态,避免下次打开模态框时残留旧输入内容。
修改后的完整代码
import { useEffect, useState } from 'react'; import { Button, FloatingLabel, Form, Modal } from 'react-bootstrap'; import getAllRequests from '../../services/getAllRequests'; import createRequest from '../../services/createRequest'; const Main = () => { const [searchedMain, setSearchedMain] = useState([]); const [loading, setLoading] = useState(true); const [show, setShow] = useState(false); const [newRequest, setNewRequest] = useState({ name: '', requestType: '', description: '', }); const handleChange = (e) => { const { name, value } = e.target; setNewRequest((prev) => ({...prev, [name]: value})); }; async function fetchData() { try { const res = await getAllRequests(); setSearchedMain(res.data); setLoading(false); } catch (err) { console.error('获取数据失败:', err); setLoading(false); } } useEffect(() => { fetchData(); }, []); const handleOpen = () => setShow(true); const handleClose = () => setShow(false); // 异步处理创建请求,确保写入完成后刷新数据 const handleSave = async () => { try { await createRequest(newRequest); // 重置表单 setNewRequest({ name: '', requestType: '', description: '', }); handleClose(); fetchData(); } catch (err) { console.error('创建请求失败:', err); // 可在此处添加用户可见的错误提示,如弹窗/Toast } }; return loading ? <h1>Loading</h1> : <> <h1>Welcome</h1> <Modal show={show} onHide={handleClose}> <Modal.Header closeButton> <Modal.Title>Add Request</Modal.Title> </Modal.Header> <Modal.Body> <Form> <FloatingLabel label="Name" className="mb-3"> <Form.Control name="name" value={newRequest.name} onChange={handleChange} /> </FloatingLabel> <FloatingLabel label="Request Type" className="mb-3"> <Form.Control name="requestType" value={newRequest.requestType} onChange={handleChange} /> </FloatingLabel> <FloatingLabel label="Description" className="mb-3"> <Form.Control name="description" value={newRequest.description} onChange={handleChange} /> </FloatingLabel> </Form> </Modal.Body> <Modal.Footer> <Button variant="secondary" onClick={handleClose}> Cancel </Button> <Button variant="primary" onClick={handleSave}> Save Changes </Button> </Modal.Footer> </Modal> <table> <thead> <tr> <th onClick={handleOpen}>Add Request</th> </tr> </thead> <tbody> {searchedMain.map((request) => { // 后续拿到自增ID后替换为request.id return ( <tr key={request.id || request.record} {...request}> <td>{request.record}</td> <td>{request.name}</td> <td>{request.requestedBy}</td> <td>{request.description}</td> </tr> ) })} </tbody> </table> </> } export default Main;
额外说明
- 需确保
createRequest函数在数据成功写入数据库后才resolve Promise,这样await才能正确等待操作完成。 - 给Form.Control绑定
value,让表单成为受控组件,避免状态不一致。 - 错误处理部分可根据需求添加用户友好的提示,比如用Toast组件展示错误信息。
内容的提问来源于stack exchange,提问作者Zanatos
相关产品推荐
相关产品推荐

