React表单API初始化后输入时其他字段重置问题排查与解决
React表单输入字段被重置问题的解决方案
问题描述
React编辑表单组件初始化时通过useEffect调用API拉取数据填充输入框,首次加载正常,但用户在某个字段输入内容时,触发的onChange会导致所有其他输入框被重置为默认初始值(API不会重复调用)。
问题根源
handleChange函数使用useCallback但依赖项为空数组,导致闭包捕获的formData始终是组件首次渲染时的初始空对象。每次调用setFormData时,都是基于这个初始值展开并修改当前字段,其他字段自然被重置为初始的空值。
最优解决方案
不需要使用localStorage,只需修改状态更新的方式,使用函数式更新来获取最新的表单状态,避免闭包带来的旧值问题:
修改后的handleChange函数
const handleChange = useCallback((e) => { let value = e.target.type === 'checkbox' ? e.target.checked : typeof e.target.value === "number" ? e.target.value : e.target.value.trim(); // 使用函数式更新,获取最新的prevFormData setFormData(prevFormData => ({ ...prevFormData, [e.target.name]: value, })); }, []);
完整修改后的Test组件代码
import React, { useEffect, useState, useCallback } from "react"; import axiosInstance from "../axios"; import { useParams } from "react-router-dom"; import Container from '@mui/material/Container'; import Typography from '@mui/material/Typography'; import EditTitle from "./EditTitle"; import EditDescription from "./EditDescription"; function Test(props) { console.log('Test Component - render') const initialFormData = Object.freeze({ id: "", title: "", description: "" }); const [formData, setFormData] = useState(initialFormData); const { id } = useParams(); async function getRecord() { let response = {}; try { response = await axiosInstance.get('records/' + id) } catch (e) { console.log(e); response.data = null; } return setFormData(response.data); }; useEffect(() => { console.log('Test Component - useEffect called') getRecord(); }, []); const handleChange = useCallback((e) => { let value = e.target.type === 'checkbox' ? e.target.checked : typeof e.target.value === "number" ? e.target.value : e.target.value.trim(); setFormData(prevFormData => ({ ...prevFormData, [e.target.name]: value, })); }, []); return ( <> {formData && <Container> <Typography>Editing record: {formData.title} {id}</Typography> <form> <EditTitle title={formData.title} handleChange={handleChange} /> <EditDescription description={formData.description} handleChange={handleChange} /> </form> </Container> } </> ); } export default Test;
补充说明
- 函数式更新的优势:React会将最新的状态作为参数传递给更新函数,确保每次状态更新都基于最新值,彻底避免闭包导致的旧值问题。
- 保留
useCallback并保持空依赖数组:因为更新函数不再依赖外部的formData,所以useCallback可以安全地使用空依赖,避免不必要的组件重渲染。
内容的提问来源于stack exchange,提问作者PhoenixDown
相关产品推荐
相关产品推荐

