【问题标题】:Why does useState cause this simple code to behave incorrectly?为什么 useState 会导致这个简单的代码行为不正确?
【发布时间】:2022-02-13 20:40:19
【问题描述】:

我编写了一个简单的组件来重现我在一个更大的项目组件中遇到的问题。

假设我有一个数组A,我想在每次按钮单击时连续添加值 1,我想在按钮单击时更新状态数组B。

export default function UseStateTest(props) {
  const arrayA = [];
  const [arrayB, setArrayB] = useState([1, 2]);

  function handleClick() {
    arrayA.push(1);
    setArrayB([3, 4]);
    console.log(arrayA);
  }

  return <button onClick={handleClick}>Test</button>;
}

那里有setArrayB,代码行为不正确,当我单击按钮时:arrayA 将始终有 1 个元素 1(我认为,根据我遇到类似问题的其他代码的经验,该代码实际上是替换元素而不是推送)。

当我将setArrayB 注释掉时,代码行为正确,每次单击按钮时都会向数组中添加一个新元素“1”。

请有人帮助我了解导致这种行为的原因。

【问题讨论】:

    标签: reactjs typescript react-hooks next.js jsx


    【解决方案1】:

    每次您的组件需要重新渲染时都会调用您的组件函数。每次调用您的组件时,您都会得到不同的arrayA(与任何其他函数一样)。这就是为什么有一个 useState 钩子(以及其他一些钩子,例如 useRef):因此您可以跨渲染保持状态信息。

    如果不调用 setArrayB,你的组件不会改变它的状态,所以 React 不会重新渲染它(不会再次调用你的函数)。 通过调用setArrayB,您正在更改组件的状态,导致重新渲染,它会执行新的调用,从而创建一个新的arrayA(和一个新的handleClick) .

    您不能在函数内的简单变量/常量中存储应该在渲染之间保留的任何信息,因为这些信息会在每次函数调用时重新创建。相反,请使用useState(用于更改时会导致组件重新渲染的状态信息)、useRef(用于不会导致组件重新渲染的状态信息 [罕见])和各种其他钩子。

    【讨论】:

    • 我明白了。非常感谢。是的,将const arrayA = []; 更改为const [arrayA, setArrayA] = useState([]);,然后进行arrayA.push(1) 工作。但是渲染组件是否需要大量时间。我正在考虑创建一个新的、较小的组件,然后将其包含在主组件中,这样只有较小的部分会被重新渲染,我想知道它是否值得做。
    • @TommyWolfheart - 这取决于您的组件为重新渲染所做的工作量。一些注意事项:push 调用打破了 React 状态的规则之一,即“不要直接修改状态”。相反,do this。如果您担心效率,您可能还想查看this,它讨论了允许子组件避免在其父组件(可能还有this)时重新渲染的各种方法。 (披露:所有都是我写的答案的链接。)
    • 非常感谢您的帮助!我会看看你分享的链接。
    • 对不起。还有一个问题。有没有一种方法可以实现[disabled, setDisabled] = useState(!prevDisabled) 的效果,如果在之前的渲染中它是true,则为按钮disabled 设置属性false。我尝试了一个 if 语句来设置变量,但我遇到了一个无限循环,我在其中声明了状态,然后在 if 语句中设置它并且循环继续。
    • @TommyWolfheart - 所以你想让disabled 在每次渲染组件时翻转?请注意,React 可以在任何时候出于任何原因重新渲染您的组件,所以这会有点……混乱。如果您真的想做那种需要存储状态信息的事情,而您不想希望在更改时导致重新渲染,您可以通过useRef 将其存储在引用中.基本上:const disabledRef = useRef(false); const disabled = (disabledRef.current = !disabledRef.current)); 但这可能不是一个好主意。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 2022-01-23
    • 1970-01-01
    • 2017-11-16
    • 1970-01-01
    • 2020-08-20
    相关资源
    最近更新 更多