试图坚持我的反应状态并在渲染上获得无限循环

Trying to persist my react state and getting infinite loop on render

当尝试使用 localStorage 来保存我的反应状态时,我得到了无限的重新渲染,我可以在开发工具中看到状态不断地被填充然后未填充。

我知道是我对 useEffect 的使用导致了这个问题,也许是我用存储的状态填充我的地图对象的条件。

设置状态项没有问题。

检索它没有。

非常感谢任何帮助。

我的代码:

  useEffect(() => {
    localStorage.myCartState ? setCart(new Map(JSON.parse(localStorage.myCartState))) 
    :
    setCart(new Map())
  }) 

useEffect(() => {
    localStorage.myCartState = JSON.stringify(Array.from(cart.entries()));
},[cart])

这是我的购物车初始状态:

const [cart, setCart] = useState(new Map())

在没有 dependency array 的情况下定义 useEffect 将导致在每次渲染时调用它。在您的 useEffect 中,您正在设置状态,这会触发渲染。这会导致无限循环。

如果您希望第一个效果仅 运行 在组件安装上,请将一个空的依赖项数组传递给它。这样的事情可能会解决问题:

useEffect(() => {
    localStorage.getItem('myCartState') ? setCart(new Map(JSON.parse(localStorage.getItem('myCartState')))) 
    :
    setCart(new Map())
, []);

有关更多信息,我建议阅读 useEffect 上的文档,其中对此进行了更详细的介绍。

除此之外,localStorage 的用法似乎不正确。当 getting/storing 数据进入 localStorage.

时,您需要使用 getItem and setItem

无论您在 localStorage.myCartState 中检索和存储什么数据,都会在您的第一个 useEffect 挂钩内的三元操作中设置其值 true,您在其中使用状态更新函数 setCart,它再次更新状态导致重新渲染,再次加载第一个 useEffect 挂钩,条件再次为真并且状态发生变化,等等。

如果您在程序中仅使用一次第一个挂钩 运行,您可以传递一个空列表 [] 作为挂钩的附加参数

useEffect(() => {
    localStorage.myCartState ? setCart(new Map(JSON.parse(localStorage.myCartState))) 
    :
    setCart(new Map())
  }, [])

否则您可能需要考虑更改您的三元操作或携带不同的 state/variable 以导致挂钩触发而不是在每次渲染期间触发。

干杯!

让我花点时间解释一下为什么,而不仅仅是回答如何解决这个问题。

useEffect 钩子有 2 个参数。回调和依赖数组,其中数组确定何时执行回调 https://reactjs.org/docs/hooks-effect.html

不行看看后面的代码

  useEffect(() => {
    localStorage.myCartState ? setCart(new Map(JSON.parse(localStorage.myCartState))) 
    :
    setCart(new Map())
  }) 

这里你传递给你的回调一个无依赖数组,这意味着“运行 每次渲染组件时的回调”

并且在回调的底部,您正在执行 setCart(new Map()) 这是状态更新。 更新状态是重新渲染的原因之一https://reactjs.org/docs/state-and-lifecycle.html,重新渲染是触发 useEffect 回调的原因,useEffect 回调正在更新状态...等等

所以,基本上您是在创建状态更新、渲染和触发回调的无限循环。

如何解决

  useEffect(() => {
    localStorage.myCartState ? setCart(new Map(JSON.parse(localStorage.myCartState))) 
    :
    setCart(new Map())
  }) 

更新您的 useEffect 以获取一个空数组以将触发器限制为第一次渲染,并注意每次您的无限重新渲染循环的原因可能是

  1. 没有传递 dep 数组
  2. 更新 dep 数组中引用的状态