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

React文本输入框二次更新后崩溃问题排查

React输入框onInput触发两次后崩溃的问题分析与解决

你的代码核心问题在于在setState的函数式更新中异步访问了已被React回收复用的合成事件对象。

React为了性能优化,会对合成事件对象进行池化处理——事件回调执行完毕后,React会清空事件对象的属性,并将currentTarget设为null,然后把这个对象放回事件池供后续事件复用。你使用了setTxt(() => e.currentTarget.value)这种函数式更新,而setState的更新函数是异步执行的,当它真正运行时,原来的事件对象e已经被回收,e.currentTarget变成了null,此时读取value自然会抛出Cannot read properties of null (reading 'value')的错误。

修复方案

方案一:提前提取值,同步更新状态(推荐)

先把输入框的值从事件对象中提取出来,再传给setState,避免异步访问回收后的事件对象:

import { useState } from "react";

export function App() {
    const [txt, setTxt] = useState("");

    return (
        <input 
            value={txt} 
            onInput={(e) => { 
                const inputValue = e.currentTarget.value;
                setTxt(inputValue); 
            }} 
        />
    );
}

方案二:函数式更新结合值提取(适合依赖旧状态的场景)

如果你的更新逻辑需要依赖之前的状态值,可以先提取当前输入值,再在函数式更新中使用:

import { useState } from "react";

export function App() {
    const [txt, setTxt] = useState("");

    return (
        <input 
            value={txt} 
            onInput={(e) => { 
                const inputValue = e.currentTarget.value;
                setTxt(prevTxt => inputValue); 
                // 示例:如果需要拼接旧值,可写成 prevTxt + inputValue
            }} 
        />
    );
}

方案三:禁用事件池化(React 16及以前可用,17+不推荐)

在React 16及更早版本中,可以调用e.persist()阻止事件对象被池化回收,但React 17之后该方法已不再生效(因为React 17改变了事件委托机制,不再池化事件对象),所以不推荐使用:

// React 16及以前版本可用
<input 
    value={txt} 
    onInput={(e) => { 
        e.persist();
        setTxt(() => e.currentTarget.value); 
    }} 
/>

总结

优先选择方案一或方案二,通过提前提取输入值的方式,避免异步访问已被回收的合成事件对象,这是最稳妥且符合React设计规范的做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:37:25