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

useState钩子的“setState”在一次调用中出现两次

孔俊捷
2023-03-14

有一个带有正方形的板,其值取决于数组,它由useStatehook处理。每次单击都会将值提高一,但不幸的是,它会将值提高两次(第一次单击除外)。

我的问题是:

(1) 为什么会发生这种情况,(2)如何避免它,以及,一般来说,(3)有没有更好的方法来处理这样一个带有钩子的数组。

let emptyBoard = Array.from({ length: parseInt(props.rows, 10) }, () =>
    new Array(parseInt(props.columns, 10)).fill(0)
  );

  const [squaresValues, setSquaresValue] = useState(emptyBoard);

  function onClick(id) {
    const [rowIndex, cellIndex] = id;
    console.log("the " + id + " square was clicked");
    setSquaresValue(prevValues => {      
      let newBoard = [...prevValues];
      console.log("before: " + newBoard[rowIndex][cellIndex]);
      newBoard[rowIndex][cellIndex] = newBoard[rowIndex][cellIndex] + 1;
      console.log("after: " + newBoard[rowIndex][cellIndex]);
      return newBoard;
    }
    );
  }

日志:

the 3,0 square was clicked 
before: 0 
after: 1 
the 3,0 square was clicked 
before: 1 
after: 2 
before: 2 
after: 3 

可以看出,从第二次点击开始,每次点击都会提高两次值。

共有2个答案

葛浩阔
2023-03-14

您仍然处于突变状态,如果您有纯组件,则它们在突变时不会重新渲染。使用JSON执行完整的状态复制。如果使用纯组件,解析是个坏主意,因为所有内容都将重新呈现。

let newBoard = [...prevValues];
newBoard[rowIndex] = [...newBoard[rowIndex]];
newBoard[rowIndex][cellIndex] =
newBoard[rowIndex][cellIndex] + 1;
郑博
2023-03-14

正如Udaya Prakash在上面的评论中提到的,它被调用了两次,以确保您的setState是独立的和幂等的。所以,如果我理解正确的话,它被调用两次不是一个错误,但是你的值在第二次被更改是。

以下是丹·阿布拉莫夫在同一期GitHub上的评论:

预计setState更新器将在开发中以严格模式运行两次。这有助于确保代码不依赖于它们运行一次(如果异步渲染被中止并更改重新启动,情况就不会如此)。如果setState更新器是纯函数(应该如此),那么这不应该影响应用程序的逻辑。

我们可以通过深度复制您的prevValues来修复它,而不是使用spread运算符进行浅复制。您可能已经知道,深度复制对象有多种方法,我们可以使用JSON。解析(JSON.stringify(…) 现在,您可以从这里用您最喜欢的种类替换它

setSquaresValue(prevValues => {
  let newBoard = JSON.parse(JSON.stringify(prevValues)); // <<< this
  console.log("before: " + newBoard[rowIndex][cellIndex]);
  newBoard[rowIndex][cellIndex] = newBoard[rowIndex][cellIndex] + 1;
  console.log("after: " + newBoard[rowIndex][cellIndex]);
  return newBoard;
});

如果你想玩的话,我已经在codesandbox中模拟过了。

 类似资料:
  • 我试图建立一个连接4的游戏,它有一个由7列组件组成的板组件,所有包含6个空间组件。每个列的上方都有一个拖放按钮,该按钮将用于将该件拖放到列中。为了在“红色”和“黑色”玩家之间交替,我创建了一个状态“redorblue”,它返回一个布尔值。 简而言之,当单击Drop按钮时,我希望切换“redorblue”的值,以跟踪轮到谁了。我已经将onClick函数设置为setState({redorblue:!

  • 因此,在重构我的基于类的聊天机器人组件以使用反应钩子的过程中,我遇到了一个使用状态钩子覆盖状态中的对象的问题。这导致只有机器人响应显示在用户界面中。当我与机器人聊天时,用户界面中显示的用户输入的闪光会被聊天机器人的响应覆盖。下面是代码: 可以这样在同一个异步函数中写入useState两次吗?如果不是,您建议我如何重构此代码,以便消息状态返回一个交替对象数组,例如:

  • 问题内容: 是否有人在React 16.8中为useState挂钩的更新部分创建了同步回调?我一直在寻找一种方法,这样我就可以使用第三方库来处理同步操作,而我似乎无法根据自己的需要来完成一项工作。 如果有人对成功完成此操作的人员有任何引用,请在此处添加。 干杯, 问题答案: 使用钩子,您不再需要该函数的回调。现在,您可以使用挂钩设置状态,并监听其值以使用挂钩更新。挂钩的可选第二个参数采用一组值来侦

  • 本文向大家介绍在React.js中使用useState钩子,包括了在React.js中使用useState钩子的使用技巧和注意事项,需要的朋友参考一下 钩子允许功能组件在反应中获得基于类的组件中可用的特性,从而使它们更加强大。 useState,我们将从react导入。从'react'导入{useState}; 这有助于我们为功能组件创建局部状态变量,并提供更新该变量的方法。 类中的状态是一个对象

  • 我正努力让你去工作。以下是功能组件: 我称之为: 我得到一个错误,如下所示: 错误:无效的钩子调用。钩子只能在函数组件的主体内部调用。发生这种情况的原因如下:1。React和渲染器(如React DOM)2的版本可能不匹配。你可能违反了Hooks 3的规则。同一应用程序中可能有多个React副本。 我已经调试并确认我使用的是单一版本。也许我使用状态钩子不正确? 这里是我调用自定义钩子的地方:

  • 我目前在Nuxt开发。和大多数初学者一样,我想知道放置API调用的最佳生命周期挂钩。我找到的许多参考资料(很像下面的参考资料)都指出,hook是在加载所有内容之前从API获取数据的最佳位置。 在Vue.js中创建和挂载事件之间的差异 当我在开发者选项的网络选项卡上注意到我在hook中的API被调用了两次时,我的问题出现了。在进一步研究之后,它声明这个钩子在服务器端和客户端上运行。我注意到只在客户端