如何用后端数据回填React Formik表单实现库存项编辑
React+Formik实现库存条目编辑:数据回填与更新
一、获取后端数据并初始化表单值
在组件挂载时,通过Axios请求后端接口获取目标条目数据,用useState存储数据,useEffect触发请求:
import { useEffect, useState } from 'react'; import axios from 'axios'; import { useParams, useNavigate } from 'react-router-dom'; const EditBoxForm = () => { const [boxData, setBoxData] = useState(null); const [isLoading, setIsLoading] = useState(true); const { boxId } = useParams(); // 从路由获取要编辑的条目ID const navigate = useNavigate(); useEffect(() => { const fetchBoxData = async () => { try { const response = await axios.get(`/api/boxes/${boxId}`); // 替换成你的后端接口 setBoxData(response.data); setIsLoading(false); } catch (error) { console.error('获取数据失败:', error); setIsLoading(false); } }; fetchBoxData(); }, [boxId]); // 加载状态处理 if (isLoading) return <div>加载中...</div>; if (!boxData) return <div>无法获取条目数据</div>; // 后续代码... }
二、动态设置Formik初始值
把写死的initialValues替换成后端返回的boxData,确保字段一一对应:
<Formik validationSchema={schema} initialValues={{ name: boxData.name || "", numberOfSets: boxData.numberOfSets || "0", sortValue: boxData.sortValue || "0", boxType: boxData.boxType || "", price: boxData.price || "", photo: boxData.photo || "", }} // 修改提交逻辑为更新操作 onSubmit={({ name, numberOfSets, sortValue, boxType, price, photo }) => { boxService.updateBox(boxId, name, numberOfSets, sortValue, boxType, price, photo); // 调用更新接口 alert("Box更新成功!"); navigate('/boxes'); // 跳转到列表页替代刷新 }} >
三、修正表单拼写错误
你的代码里存在两处拼写问题,会导致表单值异常:
Form.Item的name属性写成了sortVlaue,需改为sortValue- 错误提示误用了
errors?.numberOfBoxes,需改为errors?.sortValue
修正后的Sort Value字段:
<Form.Item name="sortValue" label="Sort Value"> <Input name="sortValue" type="number" value={values.sortValue} onChange={(e) => setFieldValue("sortValue", e.target.value)} onBlur={handleBlur} placeholder="Please enter sorting value" /> {errors?.sortValue && touched?.sortValue && ( <Text type="danger">{errors?.sortValue}</Text> )} </Form.Item>
四、完整修改后的组件代码
import { useEffect, useState } from 'react'; import axios from 'axios'; import { useParams, useNavigate } from 'react-router-dom'; import { Formik, Form } from 'formik'; import { Input, Select, Button, Text } from 'antd'; import Dropzone from 'react-dropzone'; const EditBoxForm = () => { const [boxData, setBoxData] = useState(null); const [isLoading, setIsLoading] = useState(true); const { boxId } = useParams(); const navigate = useNavigate(); useEffect(() => { const fetchBoxData = async () => { try { const response = await axios.get(`/api/boxes/${boxId}`); setBoxData(response.data); setIsLoading(false); } catch (error) { console.error('获取数据失败:', error); setIsLoading(false); } }; fetchBoxData(); }, [boxId]); if (isLoading) return <div>加载中...</div>; if (!boxData) return <div>无法获取条目数据</div>; const schema = ...; // 你的表单校验规则 const dropStyle = { border: '2px dashed #ccc', borderRadius: '4px', padding: '20px', textAlign: 'center', cursor: 'pointer', }; return ( <Formik validationSchema={schema} initialValues={{ name: boxData.name || "", numberOfSets: boxData.numberOfSets || "0", sortValue: boxData.sortValue || "0", boxType: boxData.boxType || "", price: boxData.price || "", photo: boxData.photo || "", }} onSubmit={({ name, numberOfSets, sortValue, boxType, price, photo }) => { boxService.updateBox(boxId, name, numberOfSets, sortValue, boxType, price, photo); alert("Box更新成功!"); navigate('/boxes'); }} > {({ values, errors, touched, handleBlur, handleSubmit, setFieldValue }) => { return ( <Form name="edit-gift" onFinish={handleSubmit} labelAlign="left"> <Form.Item name="name" label="Name"> <Input name="name" title="Product Name" dataIndex="name" key="productName" value={values.name} onChange={(e) => setFieldValue("name", e.target.value)} onBlur={handleBlur} placeholder="Please enter Box Name" /> {errors?.name && touched?.name && ( <Text type="danger">{errors?.name}</Text> )} </Form.Item> <Form.Item name="numberOfSets" label="Number of Sets"> <Input name="numberOfSets" type="number" value={values.numberOfSets} onChange={(e) => setFieldValue("numberOfSets", e.target.value)} onBlur={handleBlur} placeholder="Please enter Number of Sets" /> {errors?.numberOfSets && touched?.numberOfSets && ( <Text type="danger">{errors?.numberOfSets}</Text> )} </Form.Item> <Form.Item name="sortValue" label="Sort Value"> <Input name="sortValue" type="number" value={values.sortValue} onChange={(e) => setFieldValue("sortValue", e.target.value)} onBlur={handleBlur} placeholder="Please enter sorting value" /> {errors?.sortValue && touched?.sortValue && ( <Text type="danger">{errors?.sortValue}</Text> )} </Form.Item> <Form.Item name="boxType" label="Type"> <Select value={values.boxType} onChange={(value) => setFieldValue("boxType", value)} onBlur={handleBlur} placeholder="Please enter Box Type" > <Select.Option value="reward">Reward</Select.Option> <Select.Option value="doublerandom">Double Random</Select.Option> </Select> {errors?.boxType && <Text type="danger">{errors?.boxType}</Text>} </Form.Item> <Form.Item name="price" label="Price"> <Input name="price" title="Product Price" dataIndex="price" key="price" value={values.price} onChange={(e) => setFieldValue("price", e.target.value)} onBlur={handleBlur} placeholder="Please enter Box Price" /> {errors?.price && touched?.price && ( <Text type="danger">{errors?.price}</Text> )} </Form.Item> <Form.Item name="photo" label="Product Picture"> <div className="dropzone-container"> {values.photo && <img src={values.photo} alt="Product" />} {!values.photo && ( <Dropzone onDrop={(acceptedFiles) => { const fr = new FileReader(); fr.onload = () => { setFieldValue("photo", fr.result); setFieldValue("imgName", acceptedFiles[0].name); }; fr.readAsDataURL(acceptedFiles[0]); }} accept={{ "image/*": [] }} maxSize={1000000} > {({ getRootProps, getInputProps }) => ( <section> <div {...getRootProps({ style: dropStyle })}> <input {...getInputProps()} /> <p>Drag 'n' drop some files here, or click to select files</p> <aside> Tips: The size ratio of the photo is: 750:216, the maximum recommended size is 1M, and the format is: .jpg, .jpeg, .png </aside> </div> </section> )} </Dropzone> )} </div> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit">Confirm save</Button> </Form.Item> </Form> ); }} </Formik> ); }; export default EditBoxForm;
注意事项
- 确保后端返回字段名与表单
initialValues字段完全匹配 - 自行实现
boxService.updateBox方法,调用后端更新接口并传入条目ID - 优先使用路由导航替代页面刷新,提升用户体验
- 如果图片为后端存储文件,需确保返回的是可直接访问的URL
内容的提问来源于stack exchange,提问作者Hammad Yousaf
相关产品推荐
相关产品推荐

