首页 > 文章列表 > React中onChange事件为何会在输入时多次触发?

React中onChange事件为何会在输入时多次触发?

380 2025-04-03

为什么React中onChange事件会在输入时触发多次?

React 中 onChange 事件触发多次:深入探讨

在 React 开发中,输入框的 onChange 事件有时会意外触发多次,本文将深入分析此问题,并提供解决方案。

问题描述

一个简单的 React 组件,使用 useState hook 管理状态,并在输入框的 onChange 事件中更新状态并打印。然而,输入一个字符,控制台却打印了两次。这种现象在使用对象类型状态时尤其明显,而使用原始类型状态则不会出现。

示例代码片段 (问题代码):

import React, { useState } from "react";

export default function Child() {
  const [state, setState] = useState({});

  const onChange = (event) => {
    setState({ ...state, value: event.target.value });
    console.log("onChange triggered", state);
  };

  return (
    
); }

问题分析

此问题的根源在于 React 的 Strict Mode(严格模式)。在开发环境中,Strict Mode 会执行两次渲染,以帮助开发者发现潜在问题,例如不必要的副作用。

当状态为对象类型时,setState 更新的是对象的引用,而非值本身。Strict Mode 的双重渲染会导致 onChange 事件被调用两次,每次都更新相同的对象引用。 而原始类型状态(如字符串、数字)直接更新值,因此不会出现这个问题。

根本原因

  • 对象类型状态的引用更新: 使用对象作为状态时,setState 会创建一个新的对象,但 onChange 函数内的 console.log 仍然打印的是旧状态,因为 React 的异步更新机制。第二次渲染时,状态才更新为新值。
  • Strict Mode 的双重渲染: 开发环境下的 Strict Mode 触发了双重渲染,加剧了这个问题。

解决方案

避免使用对象类型状态,或者优化 setState 的调用方式:

方法一:使用原始类型状态

将状态改为原始类型,例如字符串:

import React, { useState } from "react";

export default function Child() {
  const [inputValue, setInputValue] = useState("");

  const onChange = (event) => {
    setInputValue(event.target.value);
    console.log("onChange triggered", inputValue);
  };

  return (
    
); }

方法二:使用函数式更新

使用函数式更新 setState,确保每次更新都基于最新的状态:

import React, { useState } from "react";

export default function Child() {
  const [state, setState] = useState({});

  const onChange = (event) => {
    setState((prevState) => ({ ...prevState, value: event.target.value }));
    console.log("onChange triggered", state);
  };

  return (
    
); }

通过以上方法,可以有效解决 React 中 onChange 事件触发多次的问题。 记住,生产环境中 Strict Mode 会被禁用,因此这个问题通常只在开发环境中出现。

来源:1741985317