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

React子组件useEffect重置后加载数据不触发问题

问题背景

我有一段React表单代码,核心设计分层如下:

  • FormContainer组件负责加载数据、处理表单提交逻辑、实现预填充数据加载能力,加载完成后将数据传递给子组件Form
  • Form组件只负责所有表单渲染相关逻辑
    对应实现代码如下:
import { Fragment, useEffect, useState } from "react";


const loadedState = {
    firstName:'Atul',
    lastName:'Joshi',
    fruits:'mango',
    isGoing:true
}


const initialState = {
    firstName:'',
    lastName:'',
    fruits:'',
    isGoing:false
}

const FormContainer = () => {

    const [userData,setUserData] = useState(initialState);

    const onSubmitHandler = formState =>{
        console.log(formState);
    }

    const loadData = () =>{
        console.log('setting user Dta',loadedState);
        setUserData(loadedState)
    }

    return(
        <Fragment>
            <Form onSubmit={onSubmitHandler} data={userData}></Form>
            <button type="button" onClick={loadData}>Load Data</button>
        </Fragment>
    )
}

const Form = ({onSubmit,data}) => {

    const [formState,setFormState] = useState(initialState);

    useEffect(() => {  
        console.log('form state with data ',data); // 点击重置按钮后这行日志不会触发
        setFormState(data)
    },[data]);


    const onChange = e => {
        console.log(e.target.name);
        console.log(e.target.value);
        console.log(e.target.type);
        const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
        setFormState({
            ...formState,
            [e.target.name]:value
        })
    }

    const onSubmitHandler = e => {
        e.preventDefault();
        console.log('formState = ',formState)
        onSubmit(formState);
    }

    const init = e =>{
        console.log('init..')
        setFormState(initialState)
    }


    return(  
        <form onSubmit={onSubmitHandler}>
           <span>{`Your name Is - ${formState.firstName} ${formState.lastName}`}</span>
           <label htmlFor="firstName">FirstName</label>
           <input id="firstName" name="firstName" onChange={onChange}
           value={formState.firstName}/>

           <label htmlFor="lastName">LastName</label>
           <input id="lastName" name="lastName" onChange={onChange}
           value={formState.lastName}/>
           <label htmlFor="fruits">Fruits</label>
           <select id="fruits" name="fruits" value={formState.fruits} onChange={onChange}>
                <option value="grapefruit">Grapefruit</option>
                <option value="lime">Lime</option>
                <option value="coconut">Coconut</option>
                <option value="mango">Mango</option>
           </select>

           <label htmlFor="isGoing">
                Is going:
                <input
                    name="isGoing"
                    type="checkbox" 
                    checked={formState.isGoing}
                    onChange={onChange}/>
                </label>
           <button type="submit" onSubmit={onSubmitHandler}>Submit</button>
           <button type="button" onClick={init}>Reset</button>
        </form>
    );
}

export default FormContainer;
问题现象
  • 首次点击「Load Data」按钮时,表单可以正常填充预设值
  • 点击「Reset」按钮重置表单后,后续再次点击「Load Data」按钮无法将数据加载到表单中
  • 异常表现为:Form组件中console.log('form state with data ',data)这条日志语句不会执行
问题原因

这个问题是两个逻辑问题叠加导致的:

  1. Reset逻辑只修改了子组件本地状态,没有同步父组件状态
    点击Reset按钮触发的init方法,只会把Form组件内部的formState重置为初始值,不会通知父组件FormContainer把自身维护的userData状态重置。也就是说第一次点击Load Data之后,父组件的userData就一直是loadedState对象,再也没有变过。
  2. React状态更新做引用相等判断,相同引用不会触发重渲染
    loadedState是组件外定义的全局常量,每次调用setUserData(loadedState)传入的都是同一个对象的引用。第一次调用时,userData从initialState变成loadedState,引用变化触发重渲染,传给Form的data prop更新,依赖[data]的useEffect正常执行。
    后续再点击Load Data时,React判断新旧userData是同一个对象引用,判定状态没有变化,不会触发组件重渲染,Form组件拿到的data prop也不会更新,监听data的useEffect自然不会执行,日志也就不会打印,表单无法重新填充数据。

内容的提问来源于stack exchange,提问作者Atul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:09:20