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

调用onChange时React组件重渲染导致表单输入失焦该如何解决?

问题原因及解决方案

1. 路由写法错误导致Login组件反复卸载重挂载(输入框失焦核心原因)

你在根组件的路由配置中,直接在<Route>标签内部嵌套了<Login />组件,React Router v5的这种写法下,只要根组件App触发重渲染,<Route>内的Login组件就会被销毁并重新创建实例,每次输入更新状态如果触发App重渲染,就会导致输入框被销毁重建自然失去焦点。
修复方法:将路由改成component属性或者render属性的写法:

// 修改前
<Route path="/login">
  <Login />
</Route>

// 修改后二选一即可
// 写法1:用component属性(无额外props时推荐)
<Route path="/login" component={Login} />

// 写法2:用render属性(需要传额外props时使用)
<Route path="/login" render={(routeProps) => <Login {...routeProps} />} />

2. 输入框非受控转受控异常

你初始化credentials状态时定义的是{ email: "", password: "" },但用户名输入框的name属性是username,导致初始状态下没有username字段,输入框的value初始为undefined,会被React判定为非受控组件,第一次输入后变为受控组件,也会引发异常重渲染。
修复方法:修改状态初始值:

// 修改前
const [credentials, setCredentials] = useState({ email: "", password: "" });

// 修改后
const [credentials, setCredentials] = useState({ username: "", password: "" });

3. 合成事件池回收导致的取值异常

你在onChange的状态更新回调中直接访问event.target,React的合成事件会被自动回收,异步执行的状态更新函数执行时event已经被重置,可能取不到对应的值。
修复方法:提前存好事件对象里的字段值:

const onChange = (event) => {
  // 提前取值,避免事件被回收
  const { name, value } = event.target;
  setCredentials((state) => {
    return {
      ...state,
      [name]: value,
    };
  });
};

4. 冗余代码问题

  • Login组件中已经return了完整的页面JSX,后续的return loginUI;是无效代码,且loginUI未定义,直接删除即可。
  • 导入了memo但未实际使用,如果后续需要可以用memo包裹Login组件再传给connect:export default connect(mapState, { signIn })(memo(Login))。
  • 组件内定义的location、history变量未使用,可以删除避免冗余。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 21:03:01