為什么React中onChange事件會在輸入時觸發多次?

為什么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 (     <div>       <input type="text" onChange={onChange} />     </div>   ); }

問題分析

此問題的根源在于 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 (     <div>       <input type="text" value={inputValue} onChange={onChange} />     </div>   ); }

方法二:使用函數式更新

使用函數式更新 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 (     <div>       <input type="text" onChange={onChange} />     </div>   ); }

通過以上方法,可以有效解決 React 中 onChange 事件觸發多次的問題。 記住,生產環境中 Strict Mode 會被禁用,因此這個問題通常只在開發環境中出現。

? 版權聲明
THE END
喜歡就支持一下吧
點贊14 分享