当前位置: 首页 > 知识库问答 >
问题:

javascript - react onChange 输入一个字符触发2次调用?

姜建德
2024-09-27

为什么下面代码输入一个字符后,console 会打印两次,但是把useState({}) 改成 useState(3),state从对象改成原始类型只会打印一次

import React, { useState } from "react";

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

  const onChange = () => {
    console.log("handleOnFocus", state);
  };

  return (
    <div>
      <input type="text" onChange={onChange} />
    </div>
  );
}

https://codesandbox.io/p/sandbox/react-input-functions-onfocu...
希望能解释state是对象和原始类型表现不一样的原因.

怀疑是sandbox 的bug,就中间console 打印2次。有时改了代码热更新后打印1次,刷新又打印2次。
image.png

共有2个答案

赫连智
2024-09-27

打印多次是React有意为之滴,看文档 https://legacy.reactjs.org/docs/strict-mode.html#detecting-un...

StrictMode模式, React会进行两次渲染来帮助开发者发现潜在的问题,只会在开发环境存在。

第一次渲染用于检测副作用,第二次渲染用于实际的DOM更新,原始类型数据属于非引用类型没有副作用,所以只会渲染一次

文档部分内容:
React 假设您编写的每个组件都是纯函数。这意味着您编写的 React 组件在给定相同输入(props、state 和 context)的情况下必须始终返回相同的 JSX。

违反此规则的组件会行为不可预测并导致错误。为了帮助您找到意外不纯的代码,严格模式会在开发过程中两次调用某些函数(仅调用应为纯的函数)

锺离伟彦
2024-09-27

回答

在React中,当useState的初始状态是一个对象(如{})时,并且该对象在组件的渲染之间保持不变(即引用没有改变),但对象内部的属性可能由于其他状态更新或副作用(side-effects)而发生变化,这可能导致一种看似onChange被调用了多次的错觉,实际上这是由于React的严格模式(Strict Mode)导致的。

React的严格模式会故意对类组件和函数组件进行两次挂载和更新过程的调用,以帮助开发者识别不安全的生命周期或副作用(side-effects)的使用。但是,这种双重调用不会影响到组件的状态(state)或属性(props)的更新逻辑,它仅仅是在开发环境中模拟了两次渲染过程。

然而,当组件的useState使用了一个对象作为初始状态时,由于对象的引用在组件的整个生命周期中保持不变(即使对象内部属性改变),如果你在onChange或其他副作用中打印了state,并且这些打印操作依赖于React的渲染过程(如严格模式下的双重渲染),你可能会看到两次相同的输出,但这并不意味着onChange事件处理器被调用了两次。

useState的初始状态改为原始类型(如3)时,由于原始类型的值是不可变的,且每次状态更新都会创建一个新的值,因此不会受到React严格模式双重渲染的影响,看起来就像是onChange只被调用了一次。

结论

实际上,onChange事件处理器在两种情况下都只被调用了一次。但在使用对象作为状态时,由于React的严格模式和对象的引用不变性,可能会导致开发者在控制台看到两次相同的输出。要解决这个问题,可以确保不要在副作用(如事件处理器)中打印或依赖于可能在React渲染过程中变化的状态值,除非你有明确的理由这样做。

解决方案

如果你需要在事件处理器中看到最新的状态值,确保你的状态更新逻辑是正确的,并且理解React的严格模式如何影响你的开发环境。如果确实需要调试或跟踪状态变化,考虑使用React DevTools或在useEffect中打印状态变化,这样可以更准确地反映状态的实际变化过程。

 类似资料:
  • 问题内容: 今天早些时候,我需要一次遍历2个字符的字符串,以解析格式如下的字符串(有一些额外的字母)。 我最终完成了这个工作,但是看起来很丑。我最终评论了它在做什么,因为它感觉不太明显。几乎看起来像是pythonic,但并非完全如此。 有一些更好/更清洁的方法可以做到这一点吗? 问题答案: 邓诺关于清洁剂,但还有另一种选择: 无副本版本:

  • 本文向大家介绍解释下点击一个input输入框,依次会触发哪些事件?相关面试题,主要包含被问及解释下点击一个input输入框,依次会触发哪些事件?时的应答技巧和注意事项,需要的朋友参考一下 移入-按下-获取焦点-弹起; onmouseenter→onmousedown→onfocus→onmouseup;

  • 我有一个 Blob 存储容器,其中配置了事件网格触发器(Blob 已创建)。我正在通过数据工厂加载此 blob 存储文件,很多时候,许多文件可能会在一次尝试中出现在此 blob 中。也许我们可以举一个20个文件的例子。 好消息是我的事件网格触发器启动了,函数app被调用。然而,我发现有时对于同一个文件,事件网格触发器被触发了不止一次。 在这20个文件中,很少有文件非常大,比如300 MB,但其他文

  • 问题内容: 我有一个ajax电话 现在,这里是10分钟后收到的答复。因此,ajax调用被多次调用。为什么会发生这种情况/我们如何确保ajax调用仅被调用一次? 问题答案: 禁用按钮的另一种方法是使用.one()方法,并在回调后重新绑定事件处理程序:

  • 需求是单纯做个下拉加载数据的常规功能,就是个列表不断往下加载 1.症状就是,拉到底它触发了onNearBottom也打印了,这一步没毛病。但是我往回拉一点点大概十几二十像素它又触发一次onNearBottom我这里单单一个scroll-view标签,也没有浮动精度问题,也设置了固定高。有巨佬遇到过类似的问题吗,或者有排查解决的思路吗

  • 我有一个聊天应用程序,当我在输入消息后单击按钮时,消息会发布到我的DynamoDB表中。该应用程序应该发布一次消息,但不知何故发布了两次。 管道如下: 客户端单击“发送”按钮-- 在SO的帮助下,我已经将问题隔离到我的Google Cloud函数异步调用Lambda,该函数将Lambda排队两次。 使用async,请求在实际执行之前排队。所以,如果您调用它一次,AWS将检查是否已经有一个正在执行,