【问题标题】:React executing set state twice despite being called once尽管被调用一次,但反应执行 set state 两次
【发布时间】:2022-01-06 17:33:44
【问题描述】:

当我尝试使用之前的状态更新数组时,设置状态会被执行两次。

const [countries,setCountries] = useState(["usa","china","russia"])
const [updated, setUpdated] = useState(0)

const updateCountries = () => {
  console.log("I should be printed once and being printed ONCE")
  setCountries(previous => {
    console.log("I should be printed once but being printed TWICE")
    return previous.map(country => {
      setUpdated(prev => prev+1)
      return country
    });
  })
  console.log(updated)
  // 6
}

虽然使用当前状态解决了这个问题:

const updateCountries = () => {
  console.log("I should be printed once and being printed ONCE")
  setCountries(countries.map(country => {
    setUpdated(prev => prev+1)
    return country
  }))
  console.log(updated)
  // 3
}

我在使用之前的状态时是否遗漏了一些反应规则?

更新:我无法在其他反应组件中重现此行为。因此,可能是其他组件代码触发了这种意外行为。

【问题讨论】:

  • countries 不是最初是一个数组,您调用 useState 时带有三个单独的参数(其中两个被忽略)。
  • 请提供一个minimal reproducible example,人们实际上可以运行,至少是我们可以放入基本CRA 框架或其他东西的组件。并仔细检查StrictMode
  • console.log("我应该打印一次,但会打印两次") 将只打印一次。 codesandbox.io/s/upbeat-shockley-gl26t?file=/src/App.js
  • meta.stackoverflow.com/q/338537/3001761。或者只是可以复制粘贴的整个组件,而不是随机的 sn-ps(根据您在下面的评论,它包含实际导致此问题的任何内容)。
  • 这就是为什么我们要求从 MRE 开始 - 这是基本的调试,如果你这样做了,那么在发布之前你就会知道问题出在哪里问题。

标签: reactjs react-native


【解决方案1】:

如果没有完整的代码,很难说 100%,但您的代码似乎触发了重新渲染,这就是 setCountries 运行两次的原因。它不应该与数组有关,而是与您运行事物的顺序有关。

如果您将 setCountry 和 setCountries 放在 useEffect 之外,您很可能会触发您不想要的无限重新渲染。

你可能想要的是下面的代码:

import React, { useState } from 'react';

function App() {
  const [countries, setCountries] = useState(['usa','china','russia']);
  const [country, setCountry] = useState('');

  const handleClick = () => {
    setCountries(previous => {
      console.log("I should be printed once and I am printed once", previous);
      const newArray = [...previous];
      newArray.push(country);
      return newArray;
    });
  }

  return (
    <div className="App">
      <input type="text" onChange={(e) => setCountry(e.target.value)} value={country} />
      <button onClick={handleClick}>Add Country</button>
      <ul>
        {countries && countries.map(c => <li key={c}>{c}</li>)}
      </ul>
    </div>
  );
}

export default App;

【讨论】:

  • 这些 setStates 在手动触发的函数中被调用。但是是的,它与数组无关,因为在我的应用程序的其他组件中,它也对数组执行一次。
  • @fishLegs 很酷。我简化了答案,这样您就不需要使用 useEffect。如果它解决了您的问题,请接受答案。谢谢
  • 另外请记住,每次设置使用 useState 的值时,都会触发重新渲染。如果您需要运行一些会影响其他变量的代码,您需要在重新渲染后运行的 useEffect 挂钩中执行这些操作。确保您阅读了有关钩子的内容并了解它的工作原理。
  • 我非常了解 hooks.. 使用 react hooks 多年
【解决方案2】:

因为您的代码导致 2 次重新渲染到您的组件。一个使用 setCountry,第二个 - 使用 setCountries。

【讨论】:

  • 感谢指出,但 setStates 在手动触发函数中被调用
猜你喜欢
  • 1970-01-01
  • 2017-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多