React CRUD操作更新异常:编辑第二条未修改时保存第一条旧数据
问题修复方案
问题根源
你的代码存在3个核心问题导致数据覆盖:
updateProductType状态没有在每次打开编辑弹窗时重置,第一次修改第一条数据后,该状态会一直留存第一条的修改值,后续打开其他数据的编辑弹窗只要不手动修改输入框,提交时就会把旧值传给接口- 编辑Modal被嵌套在列表的map循环中,每一条数据都会渲染一个重复的Modal,不仅冗余还会导致状态匹配错乱
- 输入框使用了
defaultValue实现非受控模式,打开新的编辑项时不会自动同步更新updateProductType状态
修复步骤
- 将编辑Modal从map循环中移出,全局只保留一个Modal实例
- 打开编辑弹窗的
updatehandleShow方法中,同时给updateProductType赋值当前选中数据的原值,清空之前的残留值 - 将输入框的
defaultValue改为value,改成受控组件和updateProductType绑定 - 关闭弹窗时额外清空
updateProductType和updateid状态,避免残留
关键修改代码
// 修改打开编辑弹窗的方法 const updatehandleShow = (_id, att_value) => { updatesetShow(true); setupdateid({ id: _id, att_value: att_value }); // 同步更新编辑状态为当前选中值 setupdateProductType(att_value); }; // 修改关闭弹窗的方法 const updatehandleClose = () => { updatesetShow(false); // 清空残留状态 setupdateid({}); setupdateProductType(""); };
输入框修改为受控模式:
<FormControl value={updateProductType} aria-label="Username" aria-describedby="basic-addon1" onChange={(e) => setupdateProductType(e.target.value)} />
同时把整个Modal组件移到map循环外,放在Card组件后面即可。
完整修复后代码
import { Button, Card, Col, FormControl, InputGroup, Modal, Row, Table, } from "@themesberg/react-bootstrap"; import React, { useEffect, useState } from "react"; import axios from "axios"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; const Bpm = () => { const [value, setValue] = useState([]); const [updateProductType, setupdateProductType] = useState(""); const [show, setShow] = useState(false); const [addProduct, setaddProduct] = useState(""); useEffect(() => { fetchData(); }, []); const fetchData = async () => { await axios .get(`${process.env.REACT_APP_API_URL}/attributes/3`) .then((response) => { setValue(response.data); }); }; const handleClose = () => setShow(false); const handleShow = () => setShow(true); const [updateshow, updatesetShow] = useState(false); const [updateid, setupdateid] = useState({}); const updatehandleClose = () => { updatesetShow(false); setupdateid({}); setupdateProductType(""); }; const updatehandleShow = (_id, att_value) => { updatesetShow(true); setupdateid({ id: _id, att_value: att_value }); setupdateProductType(att_value); }; const handleUpdate = async (e) => { e.preventDefault(); await axios .patch(`${process.env.REACT_APP_API_URL}/attributes/`, { _id: updateid.id, att_type: 3, att_value: updateProductType, }) .then((res) => console.log("updated")); fetchData(); updatehandleClose(); }; const attributeName = "BPM"; return ( <> <Card border="light" className="shadow-sm mb-4"> <Card.Body className="pb-0"> <Table responsive className="table-centered table-nowrap rounded mb-0" > <thead className="thead-light"> <tr> <th className="border-0">#</th> <th className="border-0">BPM</th> <th className="border-0"></th> </tr> </thead> <tbody> {value.map((pt, index) => { const { att_value, _id } = pt; return ( <tr key={_id}> <td> <Card.Link href="#" className="text-primary fw-bold"> {index + 1} </Card.Link> </td> <td className="fw-bold"> <FontAwesomeIcon /> {att_value} </td> <td style={{ width: "380px" }}> <Row className="d-flex align-items-center"> <Col xs={12} xl={2} className="px-0"> <small className="fw-bold"> <Button onClick={() => updatehandleShow(_id, att_value)} > 编辑 </Button> </small> </Col> </Row> </td> </tr> ); })} </tbody> </Table> </Card.Body> </Card> {/* 编辑Modal移到循环外 */} <Modal show={updateshow} onHide={updatehandleClose}> <Modal.Header closeButton> <Modal.Title>{`编辑${attributeName}`}</Modal.Title> </Modal.Header> <form onSubmit={handleUpdate}> <Modal.Body> <InputGroup> <FormControl value={updateProductType} aria-label="属性值" aria-describedby="basic-addon1" onChange={(e) => setupdateProductType(e.target.value)} /> </InputGroup> </Modal.Body> <Modal.Footer> <Button variant="secondary" onClick={updatehandleClose} > 关闭 </Button> <Button variant="primary" type="submit"> 保存修改 </Button> </Modal.Footer> </form> </Modal> </> ); }; export default Bpm;
内容的提问来源于stack exchange,提问作者hemendra
相关产品推荐
相关产品推荐

