React+Formik技术问题:API取数后表单初始值不更新及事件优化咨询
问题修复:Formik表单不更新API数据 + React搜索回车最佳实践
一、Formik表单无法加载API数据的问题修复
问题根源
data初始状态设为数组[],但API返回的是单个员工对象,数组无法匹配Formik需要的键值对结构,导致initialValues={data || initialValues}在初始时取到无效数组,Formik无法正确渲染表单值。- 条件判断
data !== undefined逻辑有误,初始数组[]不等于undefined,会直接渲染Formik,但此时data是无效结构。
修复步骤
- 将
data的初始状态改为null,明确表示未获取到数据:const [data, setData] = useState(null); - 调整条件渲染逻辑,仅当
data存在时渲染Formik:{data ? ( <Formik ... /> ) : ( <div style={{fontSize: "14px", color:"crimson"}}>Not available</div> )} - 确保API返回的数据键名和
initialValues完全一致(比如zoon_no需和后端返回字段匹配)。
二、搜索输入框回车事件的React最佳实践
问题根源
全局监听document的keydown事件会影响页面其他元素,不符合React组件化思维,应仅监听目标输入框的事件。
修复步骤
- 移除全局监听逻辑,封装单独的搜索函数:
const handleSearch = async (e) => { if (e.keyCode === 13) { e.preventDefault(); if (!query.trim()) return; // 空查询不触发请求 setLoading(true); try { const res = await axios.get(`http://localhost:3001/alameia/search/edit?q=${query}`); setData(res.data); } catch (err) { if (err.response) { console.log(err.response.data); console.log(err.response.status); } else if (err.request) { console.log(err.request); } else { console.log('Error', err.message); } } finally { setLoading(false); } } }; - 给搜索输入框绑定
onKeyDown事件,仅监听当前输入框的回车:<input type="text" placeholder="بحث" id="search" value={query} onChange={(e) => setQuery(e.target.value)} onKeyDown={handleSearch} />
修改后的完整代码
import React, { useState } from 'react'; import { Formik, Form, FastField } from 'formik'; import SearchOutlinedIcon from "@mui/icons-material/SearchOutlined"; import * as yup from 'yup'; import axios from 'axios'; import "./edit.scss"; import Loading from "../Loading"; import Swal from 'sweetalert2'; const validation = yup.object().shape({ emp_no: yup.number().required(""), name: yup.string().required(""), project: yup.string().required(""), nationality: yup.string().required(""), iqama_no: yup.number().required(""), room_no: yup.number().required(""), zoon_no: yup.number().required(""), in_date: yup.date().required(""), in_reason: yup.string().required(""), out_date: yup.date() }); const initialValues = { emp_no: "", name: "", project: "", nationality: "", iqama_no: "", room_no: "", zoon_no: "", in_date: "", in_reason: "", out_date: "", }; const EditAlameia = () => { const [query, setQuery] = useState(""); const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const handleSearch = async (e) => { if (e.keyCode === 13) { e.preventDefault(); if (!query.trim()) return; setLoading(true); try { const res = await axios.get(`http://localhost:3001/alameia/search/edit?q=${query}`); setData(res.data); } catch (err) { if (err.response) { console.log(err.response.data); console.log(err.response.status); } else if (err.request) { console.log(err.request); } else { console.log('Error', err.message); } } finally { setLoading(false); } } }; if (loading) { return <Loading />; } return ( <div className="searchNew"> <div className="top"> <h5>Edit Data</h5> <div className="searchInput"> <input type="text" placeholder="بحث" id="search" value={query} onChange={(e) => setQuery(e.target.value)} onKeyDown={handleSearch} /> <SearchOutlinedIcon /> </div> </div> {data ? ( <Formik initialValues={data} validationSchema={validation} enableReinitialize > {formik => ( <Form encType='multipart/form-data'> <div className="bottom"> <div className="right"> <label htmlFor="emp_no">الرقم الوظيفي</label> <FastField type='number' name='emp_no' id="emp_no" /> <label htmlFor="name">الإسم</label> <FastField type='text' name='name' id="name" /> <label htmlFor="project">المشروع</label> <FastField type='text' name='project' id="project" /> <label htmlFor="nationality">الجنسية</label> <FastField type='text' name='nationality' id="nationality" /> <button type='submit' className="btn btn-danger">Update</button> </div> <div className="left"> <div className="room"> <label htmlFor="room_no">رقم الغرفة</label> <FastField autoComplete="off" className="formInput" type="number" id="room_no" name="room_no" placeholder="" /> <label htmlFor="zoon_no">زون</label> <FastField className="formInput" type="number" id="zoon_no" name="zoon_no" placeholder="" /> </div> <label htmlFor="in_date">تاريخ التسكين</label> <FastField type='date' name='in_date' id="in_date" /> <label htmlFor="iqama_no">رقم الإقامة</label> <FastField type='number' name='iqama_no' id="iqama_no" /> <label htmlFor="in_reason">سبب التسكين</label> <FastField type='text' name='in_reason' id="in_reason" /> <label htmlFor="out_date">تاريخ الخروج</label> <FastField type='date' name='out_date' id="out_date" /> </div> </div> </Form> )} </Formik> ) : ( <div style={{ fontSize: "14px", color: "crimson" }}>Not available</div> )} </div> ); }; export default EditAlameia;
额外优化点
- 修正了label的
htmlFor属性,原代码中部分label的for值和input的id不匹配,导致点击label无法聚焦对应输入框,现已修正。 - 增加空查询判断,避免无效API请求。
内容的提问来源于stack exchange,提问作者a7med
相关产品推荐
相关产品推荐

