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

React+Formik技术问题:API取数后表单初始值不更新及事件优化咨询

问题修复:Formik表单不更新API数据 + React搜索回车最佳实践

一、Formik表单无法加载API数据的问题修复

问题根源

  1. data初始状态设为数组[],但API返回的是单个员工对象,数组无法匹配Formik需要的键值对结构,导致initialValues={data || initialValues}在初始时取到无效数组,Formik无法正确渲染表单值。
  2. 条件判断data !== undefined逻辑有误,初始数组[]不等于undefined,会直接渲染Formik,但此时data是无效结构。

修复步骤

  1. 将data的初始状态改为null,明确表示未获取到数据:
    const [data, setData] = useState(null);
    
  2. 调整条件渲染逻辑,仅当data存在时渲染Formik:
    {data ? (
      <Formik ... />
    ) : (
      <div style={{fontSize: "14px", color:"crimson"}}>Not available</div>
    )}
    
  3. 确保API返回的数据键名和initialValues完全一致(比如zoon_no需和后端返回字段匹配)。

二、搜索输入框回车事件的React最佳实践

问题根源

全局监听document的keydown事件会影响页面其他元素,不符合React组件化思维,应仅监听目标输入框的事件。

修复步骤

  1. 移除全局监听逻辑,封装单独的搜索函数:
    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);
        }
      }
    };
    
  2. 给搜索输入框绑定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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 12:01:18